Android中動畫分為三種:
- 逐幀動畫
- 補間動畫
- 屬性動畫
逐幀動畫
逐幀動畫類似于gif或是電影的原理,通過將一系列圖片連續(xù)播放來獲得動畫效果。它本質(zhì)是一種Drawable,由ImageView播放。
定義逐幀動畫有兩種方式:
drawable文件夾下定義xml:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="boolean">
<item
android:drawable="@..."
android:duration="integer"/>
<item .../>
</animation-list>
android:oneshot
指示是否重復播放
java代碼:
創(chuàng)建AnimationDrawable
對象,使用addFrame(Drawable frame, int duration)
向動畫添加幀。
AnimationDrawable默認是不播放的,調(diào)用start()
、stop()
來控制動畫的播放和停止。
補間動畫
補間動畫指定動畫開始和結(jié)束時的狀態(tài)(透明度、大小、位移、旋轉(zhuǎn)等),由系統(tǒng)根據(jù)指定的Interpolator(插值器)來生成過程幀,并實現(xiàn)動畫過程。
補間動畫有個很明顯的缺點,動畫改變的只是顯示,并沒有改變事件響應的位置。比方說我們通過補間動畫將Button移到了另一個位置,但是我們依然得點Button原來的位置才能觸發(fā)Button的點擊事件。
動畫的顯示會依賴于父控件的大小,若父控件太小,動畫可能會移出父控件邊緣,導致動畫不可見。
創(chuàng)建動畫的基本流程:
- 創(chuàng)建動畫實例
- 設置動畫持續(xù)時間、插值器等
- 調(diào)用view的
startAnimation()
方法并傳入動畫實例
- 透明度動畫
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
view.startAnimation(alphaAnimation)
0代表完全透明,1為不透明。
- 旋轉(zhuǎn)動畫
RotateAnimation rotateAnimation = new RotateAnimation(0, 720, 75, 75); // 開始角度、結(jié)束角度、旋轉(zhuǎn)中心X坐標、旋轉(zhuǎn)中心Y坐標(此處X,Y是以View自身為參考系)
RotateAnimation rotateAnimation = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 2f, Animation.RELATIVE_TO_SELF, 2f);// 開始角度、結(jié)束角度、X旋轉(zhuǎn)參考,X方向上與自身大小比值、Y旋轉(zhuǎn)參考,Y方向上與自身大小比值(參考系依然為View本身)
旋轉(zhuǎn)動畫可指定旋轉(zhuǎn)中心的坐標與參考View寬高的比值,RELATIVE_TO_SELF
或RELATIVE_TO_PARENT
,值得注意的是,X,Y的坐標始終是以View自身為參考系。
- 位移動畫
TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 300);// 起始X、結(jié)束X、起始Y、結(jié)束Y
TranslateAnimation translateAnimation = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_SELF, 1,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 2);// 相對方式
- 縮放動畫
ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 2, 0.5f, 2);// 數(shù)字表倍率
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);// 指定縮放中心坐標
-
動畫集合
通過AnimationSet,可以組合各種動畫,使其同時播放
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.setInterpolator(new AccelerateInterpolator());
animationSet.setDuration(1000);
image.startAnimation(animationSet);
-
監(jiān)聽器
有時候我們需要監(jiān)聽動畫的開始或結(jié)束等來做進一步操作,這時候可以對動畫設置監(jiān)聽器:
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
屬性動畫
屬性動畫,顧名思義,是對針對屬性的動畫,通過持續(xù)地改變某個屬性來實現(xiàn)View的動畫效果。與補間動畫不同,屬性動畫真實地改變了View的屬性值。
- ObjectAnimator
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(button, "translationX", 300);
objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator.setDuration(300);
objectAnimator.start();
要操作的屬性必須具有g(shù)et和set方法。如果屬性沒有g(shù)et、set方法,可以自定義一個包裝類:
private static class WrapperView {
private View mTarget;
public WrapperView(View target) {
this.mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
- PropertyValuesHolder
要同時針對多個屬性進行動畫時使用:
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("translationX", 300);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("scaleX", 1, 0.1f);
PropertyValuesHolder propertyValuesHolder3 = PropertyValuesHolder.ofFloat("scaleY", 1, 0.1f);
ObjectAnimator.ofPropertyValuesHolder(button, propertyValuesHolder1, propertyValuesHolder2, propertyValuesHolder3).setDuration(1000).start();
-
ValueAnimator
ValueAnimator更像是一個數(shù)值發(fā)生器,使用時通過監(jiān)聽數(shù)值的變換來自己完成動畫的實現(xiàn):
ValueAnimator animator = ValueAnimator.ofFloat(0, 100);
animator.setTarget(view);
animator.setDuration(1000).start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
// TODO use the value
}
});
-
動畫時間監(jiān)聽
一個完整動畫有四個過程:start、repeat、end、cancel。有兩種監(jiān)聽器可以選:
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
或:
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
AnimatorListenerAdapter是AnimatorListener的實現(xiàn)類,可以按需要實現(xiàn)監(jiān)聽start、repeat、end、cancel、pause、resume過程。
-
AnimatorSet
AnimatorSet 不能能像PropertyValuesHolder那樣同時實現(xiàn)多個動畫,同時還能精準控制動畫的順序:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(button, "translationX", 300);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(button, "scaleX", 1, 0, 1);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(button, "scaleY", 1, 0, 1);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playTogether(animator1, animator2, animator3);
set.start();
playTogether、playSequentially、play().with()、play().before()、play().after()等來控制動畫順序。
- xml中使用屬性動畫
animator文件夾下xml:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType">
</objectAnimator>
java代碼中:
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scalex);
animator.setTarget(view);
animator.start();
- view的animate方法
button.animate().alpha(0).y(300).setDuration(300)
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
}
})
.start();
下面有幾篇郭霖大神的進階文章:
Android屬性動畫完全解析(上),初識屬性動畫的基本用法
Android屬性動畫完全解析(中),ValueAnimator和ObjectAnimator的高級用法
Android屬性動畫完全解析(下),Interpolator和ViewPropertyAnimator的用法
布局動畫
布局動畫是作用在ViewGroup上當布局中View增加的動畫過渡效果。可在xml中添加android:animateLayoutChanges="true"
,為布局添加默認動畫。
java中自定義動畫:
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
sa.setDuration(1000);
LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f); // 第二個參數(shù)是延遲
lac.setOrder(LayoutAnimationController.ORDER_NORMAL); // 當延遲不為0時,可指定View顯示順序,還有隨機和反序
ll.setLayoutAnimation(lac);
- Cursor
Cursor是ContentProvider和數(shù)據(jù)庫的查詢結(jié)果集,類似于一張擁有很多行列的表,每一列即Column有特定的name,使用cursor.moveToNext()時,相當于當前行指示向下移動一行,通過cursor.getXXX(int columnIndex)方法獲得表中這一行對應列的值。