目錄
Android高級動畫(1)http://www.lxweimin.com/p/48554844a2db
Android高級動畫(2)http://www.lxweimin.com/p/89cfd9042b1e
Android高級動畫(3)http://www.lxweimin.com/p/d6cc8d218900
Android高級動畫(4)http://www.lxweimin.com/p/91f8363c3a8c
為什么要學(xué)好動畫
動畫在移動App開發(fā)中的重要性不言而喻,通俗點講,動畫可以讓我們的App界面不那么死板,可以帶來酷炫的交互效果,用Material Design專業(yè)點的說法,動畫是一種高級的用戶反饋,對用戶操作、選擇結(jié)果的一種反饋,對程序執(zhí)行過程的動態(tài)展示,對用戶視覺和注意力的引導(dǎo),幫助用戶更好地理解App的功能設(shè)計,Android5.0新生的動畫更是體現(xiàn)出這個理念。所以從這點上說,動畫的意義遠(yuǎn)不止酷炫這一層面。
那么我們就更加有理由要學(xué)好動畫,把動畫應(yīng)用到我們的項目中去。從這篇文章開始,我們將會全面地學(xué)習(xí)Android中的動畫系統(tǒng)。我們會講到每一種動畫的原理、使用方法、應(yīng)用場景、優(yōu)缺點等,關(guān)于矢量動畫,由于原理和實現(xiàn)方式相對復(fù)雜,我們會花比較大的篇幅來學(xué)習(xí)。最后,我們會封裝一個通用動畫庫來簡化動畫的使用。
OK,那我們廢話少說,開始一場愉快的Android動畫之旅吧!
大綱
Tween動畫
Tween動畫是Android最早的動畫框架,從Android1.0就開始提供。Tween動畫使用簡單,功能也不強(qiáng),支持代碼和xml兩種方式編寫動畫。我們來看一個演示:
這是一個常規(guī)的Tween動畫,用xml編寫動畫,用AnimationUtils加載動畫,實現(xiàn)如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true">
<rotate android:fromDegrees="0"
android:toDegrees="359"
android:duration="1000"
android:repeatCount="1"
android:repeatMode="reverse"
android:pivotX="50%"
android:pivotY="50%"/>
</set>
LinearLayout layout = (LinearLayout)findViewById(R.id.layout_1);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.tween_1);
layout.startAnimation(animation);
Tween動畫使用起來簡單,效果也比較流暢,但是缺點也是很明顯,首先就是拓展性太差,只能寫移動、縮放、旋轉(zhuǎn)、漸變四種動畫,以及這四種動畫的組合,不支持自定義View的拓展。其次一個致命的缺點就是動畫只是屏幕繪制上的動畫,控件的屬性并沒有改變,一個經(jīng)典的問題就是一個Button從一個地方移動到另一個地方,點擊事件還是在原來的地方。所以Tween動畫我們現(xiàn)在也基本放棄了,所有使用Tween動畫的場景都可以用屬性動畫來替代。
下面屬性動畫閃亮登場
屬性動畫
屬性動畫是Android3.0版本推出的動畫框架,其功能和拓展性都很強(qiáng)。它不僅能實現(xiàn)所有Tween動畫的功能,還有很強(qiáng)的拓展性,根本原因是屬性動畫從本質(zhì)上已經(jīng)完全擺脫了控件,雖然我們大多數(shù)情況下使用屬性動畫都是給控件做動畫,但是屬性動畫的底層只是一個數(shù)值發(fā)生器,和控件沒有半毛錢關(guān)系。
[數(shù)值發(fā)生器]
ValueAnimator:數(shù)值發(fā)生器,這是屬性動畫的根本,ValueAnimator的功能就是在兩個數(shù)值范圍內(nèi),順序地產(chǎn)生過渡數(shù)值,過渡速率可以通過Intepolator來控制,過渡時間通過duration來設(shè)置,最終產(chǎn)生一組有特定變化速率的數(shù)值序列。那這個數(shù)值序列產(chǎn)生了干嘛呢?你想干嘛就干嘛。
ValueAnimator animator = ValueAnimator.ofFloat(0, 100);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float fraction = valueAnimator.getAnimatedFraction(); // 當(dāng)前動畫進(jìn)度百分比,范圍是0-1
float value = (float)valueAnimator.getAnimatedValue(); // 當(dāng)前動畫值,范圍是ofFloat的參數(shù)
}
});
[應(yīng)用動畫]
通過ValueAnimator我們得到了一組變化的數(shù)值序列,大多數(shù)情況下我們都是拿來給控件做動畫,實現(xiàn)如下:
ValueAnimator animator = ValueAnimator.ofFloat(0, 360);
animator.setDuration(1000);
animator.setInterpolator(new AccelerateInterpolator());
animator.setRepeatCount(1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = (float)valueAnimator.getAnimatedValue();
imageView.setRotationY(rotate);
}
});
animator.start();
我們使用ValueAnimator產(chǎn)生一組0-360的數(shù)值序列,數(shù)值變化速率遵循AccelerateInterpolator函數(shù),時間為1000毫秒,然后在回調(diào)函數(shù)里我們可以獲取當(dāng)前動畫值value,然后調(diào)用imageView.setRotationY(value);這樣就實現(xiàn)了imageView的旋轉(zhuǎn)動畫。效果如下:
[應(yīng)用拓展]
上面產(chǎn)生的數(shù)值序列,我們除了可以用來做動畫,還可以用在任何你能想到的地方。比如我們有一個TextView顯示金額,這個金額要動畫地從0增加到2000,這就可以用ValueAnimator。
ValueAnimator animator = ValueAnimator.ofFloat(0, 2000);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = (float)valueAnimator.getAnimatedValue();
textView.setText(String.valueOf(value));
}
});
animator.start();
效果如下:
[ObjectAnimator]
可能你已經(jīng)注意到了,ValueAnimator是屬性動畫底層的數(shù)值發(fā)生器,雖然拓展性很強(qiáng),但是用它來寫動畫實在是麻煩,這一點Google當(dāng)然也想到了,于是ObjectAnimator就誕生了,它把ValueAnimator封裝在里面,我們用它可以簡單地實現(xiàn)對控件的動畫。代碼如下:
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "rotationY", 0, 359);
animator.setDuration(1000);
animator.setRepeatCount(1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.start();
效果和上面是一樣的
第一行代碼有三個參數(shù),分別是做動畫的控件, 需要動畫的屬性名,第三個是可變參數(shù),表示動畫值的范圍。其中屬性名是一個字符串,ObjectAnimator會根據(jù)這個屬性名拼一個set[屬性名](setRotationY)方法,然后用反射調(diào)用,從而實現(xiàn)動畫。
[自定義View]
既然ValueAnimator可以用在任何地方,那當(dāng)然也可以用在自定義View。我寫了一個很簡單的自定義View,就是畫一個扇形,扇形的角度由一個叫fraction的屬性決定。我們在自定View中需要做動畫的屬性一定要有一個setFraction方法,以便讓屬性動畫通過反射調(diào)用。
ObjectAnimator animator = ObjectAnimator.ofFloat(customView, "fraction", 0, 1);
animator.setDuration(2000);
animator.start();
效果如下:
[Path動畫]
5.0之后,ObjectAnimator還有一個強(qiáng)大的功能,那就是根據(jù)一個Path路徑做動畫,先看效果:
這樣的效果要讓我們自己寫還是要費點事的,但是用ObjectAnimator來做就太簡單了:
ObjectAnimator animator = ObjectAnimator.ofFloat(iv, View.X, View.Y, path);
animator.setDuration(2000);
animator.setRepeatCount(1);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.start();
什么?和正常的用法基本一樣?是的,區(qū)別就是ObjectAnimator.ofFloat方法的重載,傳四個參數(shù),第一個是做動畫的控件,第二和第三個是動畫的方向,第四個就是動畫的Path路徑,就是這么簡單,剩下的就是構(gòu)建Path了,Path的構(gòu)建你可以隨心所欲。你能構(gòu)建出多酷炫的Path,它就能展示多酷炫的動畫。
Interpolator
Interpolator翻譯叫插值器,它是個好東西,它用來控制動畫過程的變化速率,沒有它我們的動畫將會一直勻速變化,如果要自己控制變化速率那也太麻煩了。Android中Interpolator總共有8種。
1、[Linear]
2、[Accelerate]
3、[Decelerate]
4、[AccelerateDecelerate]
5、[Anticipate]
6、[Overshoot]
7、[Bounce]
8、[Cycle]
幀動畫
幀動畫是一個比較簡單的動畫框架,原理就像播放幻燈片一樣,傳一組圖片進(jìn)去,然后依次循環(huán)播放,可以設(shè)置每一張圖片的播放時間。幀動畫可以通過xml創(chuàng)建,也可以java代碼動態(tài)構(gòu)建,使用起來還是比較方便的。先看效果:
代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@mipmap/run_1" android:duration="150" />
<item android:drawable="@mipmap/run_2" android:duration="150" />
<item android:drawable="@mipmap/run_3" android:duration="150" />
<item android:drawable="@mipmap/run_4" android:duration="150" />
</animation-list>
ImageView image = (ImageView) findViewById(R.id.iv_1);
image.setImageResource(R.drawable.animation_list);
AnimationDrawable anim = (AnimationDrawable) image.getDrawable();
anim.start();
可以看出來幀動畫的使用還是比較簡單的,但是缺點也很明顯,就是動畫不連續(xù)。如果要想動畫連續(xù)也簡單,就把圖片做的多一點,每張圖片只漸變一點點。但是這樣隨之而來的另一個問題就是圖片太多,體積太大。所以也只能在圖片流暢度和圖片數(shù)量體積之間做一個平衡。這點比較尷尬。但是一般來說用來做一個動畫的小Logo還是夠用的。
CircularReveral
這是Android5.0推出的新的動畫框架,可以給View做一個揭露效果。效果如下:
效果相當(dāng)贊有木有!代碼實現(xiàn)也很簡單:
Animator anim = ViewAnimationUtils.createCircularReveal(oval, oval.getWidth() / 2, oval.getHeight() / 2, oval.getWidth(), 0);
anim.setDuration(2000);
anim.start();
Animator anim = ViewAnimationUtils.createCircularReveal(rect, 0, 0, 0, (float) Math.hypot(rect.getWidth(), rect.getHeight()));
animator2.setDuration(2000);
animator2.start();
五個參數(shù)分別是View,中心點坐標(biāo),開始半徑,結(jié)束半徑。通過這五個參數(shù)的配合,我們可以做出很多不同的效果。
Activity轉(zhuǎn)場動畫
1、傳統(tǒng)轉(zhuǎn)場動畫
傳統(tǒng)轉(zhuǎn)場動畫我們再熟悉不過了,不再多說,直接看效果:
代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%"
android:toXDelta="0%"
android:duration="500" />
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%"
android:toXDelta="-40%"
android:duration="500" />
</set>
startActivity(new Intent(this, Activity2.class));
overridePendingTransition(R.anim.slide_right_in, R.anim.slide_left_out);
2、5.0新轉(zhuǎn)場動畫
這個厲害了!5.0新的轉(zhuǎn)場動畫分為4種,Explode、Slide、Fade、Share,傳統(tǒng)的轉(zhuǎn)場動畫只能作用于整個頁面,不能對頁面中的單個元素做控制,而5.0新轉(zhuǎn)場動畫可以控制頁面中的每個元素,根據(jù)元素動畫方式,分為4大類。
我們先來看下四種效果:
(1)Explode
Explode的效果是下一個頁面的元素從四面八方進(jìn)入,最終形成完整的頁面。代碼如下:
// 跳轉(zhuǎn)
Intent intent = new Intent(this, CActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
// 跳轉(zhuǎn)的Activity
public class CActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setEnterTransition(new Explode());
setContentView(R.layout.activity_c);
}
}
在跳轉(zhuǎn)時就要注意一點,intent后面還要再傳一個參數(shù)bundle,固定寫法ActivityOptions.makeSceneTransitionAnimation(this).toBundle(),下一個Activity根據(jù)這個就能識別出使用5.0新轉(zhuǎn)場動畫。
跳轉(zhuǎn)的Activity在onCreate方法中,調(diào)用getWindow().setEnterTransition(new Explode());即可,注意要在setContentView之前哦。
(2)Slide
Slide就是下一個頁面元素從底部依次向上運動,最終形成完整的頁面。代碼如下:
// 跳轉(zhuǎn)
Intent intent = new Intent(this, CActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
// 跳轉(zhuǎn)的Activity
public class CActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setEnterTransition(new Slide());
setContentView(R.layout.activity_c);
}
}
和Explode幾乎沒有什么區(qū)別,就是跳轉(zhuǎn)的Activity在onCreate方法中設(shè)置transition為Slide即可。
(3)Fade
Fade就是下一個頁面元素漸變出現(xiàn),最終形成完整的頁面。代碼如下:
// 跳轉(zhuǎn)
Intent intent = new Intent(this, CActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
// 跳轉(zhuǎn)的Activity
public class CActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setEnterTransition(new Fade());
getWindow().setExitTransition(new Fade());
setContentView(R.layout.activity_c);
}
}
同樣,就是跳轉(zhuǎn)的Activity在onCreate方法中設(shè)置transition為Fade即可,只不過這里要最好要同時設(shè)置Enter和Exit。
(4)Share
Share是最復(fù)雜的一種轉(zhuǎn)場方式,在跳轉(zhuǎn)的兩個Activity之間,如果有相同的View元素,那么,兩個元素就可以設(shè)置成共享狀態(tài),在跳轉(zhuǎn)時,這個View就會從第一個Activity的顯示狀態(tài)過渡到第二個Activity的顯示狀態(tài),給用戶的感覺仿佛是兩個Activity共享一個View。
我們再來單獨看下Share的效果:
很酷炫有木有有木有
前后兩個Activty都有兩個共同的元素,一個機(jī)器人Logo,一個Android文字,但是它們在兩個Activity中的位置、大小、顏色都不一樣。于是,在兩個Activity跳轉(zhuǎn)過程中,位置、大小、顏色會自動有一個漸變的過程,從第一個Activity的狀態(tài)漸變到第二個Activity的狀態(tài)。從而給人一種兩個Activity共享元素的感覺。
代碼如下:
<!-- 首先,兩個Activity共享的元素需要設(shè)置相同的transitionName: android:transitionName="fab" -->
<Button
android:id="@+id/fab_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@mipmap/ic_launcher"
android:elevation="5dp"
android:onClick="explode"
android:transitionName="fab" />
<Button
android:id="@+id/fab_button"
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_alignParentEnd="true"
android:layout_below="@id/holder_view"
android:layout_marginTop="-80dp"
android:background="@mipmap/ic_launcher"
android:elevation="5dp"
android:transitionName="fab" />
// 跳轉(zhuǎn)時,要為每一個共享的view設(shè)置對應(yīng)的transitionName
View fab = findViewById(R.id.fab_button);
View txName = findViewById(R.id.tx_user_name);
intent = new Intent(this, CActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,
Pair.create(view, "share"),
Pair.create(fab, "fab"),
Pair.create(txName, "user_name"))
.toBundle());
// 跳轉(zhuǎn)的Activity在onCreate方法中開啟Transition模式
public class CActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
setContentView(R.layout.activity_c);
}
}
實現(xiàn)代碼看上去比較多,實際也比較簡單。畢竟這么酷炫的轉(zhuǎn)場動畫化,多寫兩行代碼也值得。
(5)Share轉(zhuǎn)場的經(jīng)典應(yīng)用
Share轉(zhuǎn)場這種方式最經(jīng)典的應(yīng)用就是列表頁跳詳情頁。因為通常列表頁和詳情頁都會包含相同View元素,使用Share轉(zhuǎn)場給人一種連續(xù)過渡效果,體驗非常棒。
下面看一個簡單的示例:
好了,Activity轉(zhuǎn)場就講到這里,充分利用這些動畫,可以做出非常精彩的轉(zhuǎn)場效果。
下一篇
OK,Android高級動畫第一篇就到這里了,為什么不講完呢?因為下一篇我們要上點兒硬貨,來講講Android矢量動畫,徹底顛覆傳統(tǒng)的動畫方式。牛逼酷炫掉渣天的動畫效果正在等著你。