逐幀動畫
逐幀動畫也叫 Drawable Animation,是最簡單最直觀的動畫效果。
在Android 中實現逐幀動畫就是由設計師給出一系列狀態不斷變化的圖片,開發者就指定這些圖片顯示的持續時間,然后順序開始播放這些圖片,就形成了動畫了。
使用逐幀動畫 既可以使用XML的方法實現,也可以使用代碼來實現。
XML
首先把資源文件(每一幀的圖片)放在 res/drawable 下。 如圖:
然后在這里 新建一個XML文件。 在這個文件中使用的 <animation-list>標簽來定義動畫。使用<item>標簽來定義動畫的每一幀,并在每一個<item>中指定自己的屬性,例如 持續時間 android:duration="300" 、 這一幀使用的圖片 android:drawable="@drawable/z_1_die_01" 。
frme_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/z_1_die_01"
android:duration="300"/>
<item
android:drawable="@drawable/z_1_die_02"
android:duration="300"/>
<item
android:drawable="@drawable/z_1_die_03"
android:duration="300"/>
<item
android:drawable="@drawable/z_1_die_04"
android:duration="300"/>
<item
android:drawable="@drawable/z_1_die_05"
android:duration="300"/>
</animation-list>
android:oneshot 來控制動畫是否循環播放, false 表示 循環播放 , true 表示 不循環播放 。
在控件的布局中給控件使用這個 drawable 文件
<ImageView
android:id="@+id/iv_frame_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/frme_animation"/>
定義好了這個動畫,為了讓動畫播放,就要使用代碼讓他開始播放,代碼如下:
//xml
ImageView ivFrameXml = (ImageView) findViewById(R.id.iv_frame_xml);
AnimationDrawable background = (AnimationDrawable)ivFrameXml.getDrawable();
background.start();
代碼方式
代碼的方式更加簡單,新建一個 AnimationDrawable ,并為他增加每一幀的圖片和持續時間就可以了。
//code
ImageView ivFrameCode = (ImageView) findViewById(R.id.iv_frame_code);
AnimationDrawable animationDrawable = new AnimationDrawable();
for (int i = 1; i <= 5; i++) {
int id = getResources().getIdentifier("z_1_die_0" + i, "drawable", getPackageName());
Drawable drawable = getResources().getDrawable(id);
animationDrawable.addFrame(drawable,300);
}
ivFrameCode.setImageDrawable(animationDrawable);
//循環播放
animationDrawable.setOneShot(false);
//開始播放
animationDrawable.start();
效果如圖所示:
補間動畫
補間動畫無須再知道動畫過程中的每一幀了,只需要定義動畫的開始和結束,并且指定變化的時間和方式就可以了,他會自動補全中間的過程。Android會通過所給出的開始值與結束值,再根據中間變化的規律,最后計算出每一幀圖片顯示的效果,最后直接顯示出來。
主要包括這四種基本效果:透明度變化 Alpha 、縮放變化 Scale 、 位移變化 Translate 、旋轉變化 Rotate 。這四種效果可以動態組合,從而實現復雜的動畫。
插值器 Interpolator
補間動畫能夠自己補充中間的內容,其實靠的就是這個。
Interpolator 會根據類型不同,選擇不同的算法計算出補間動畫所需要動態插入的密度和位置,Interpolator 負責控制動畫的變化速度,他可以 勻速、加速、減速、拋物線等多種變化。
public interface Interpolator extends TimeInterpolator {
// A new interface, TimeInterpolator, was introduced for the new android.animation
// package. This older Interpolator interface extends TimeInterpolator so that users of
// the new Animator-based animations can use either the old Interpolator implementations or
// new classes that implement TimeInterpolator directly.
}
public interface TimeInterpolator {
/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation time.
*
* @param input A value between 0 and 1.0 indicating our current point
* in the animation where 0 represents the start and 1.0 represents
* the end
* @return The interpolation value. This value can be more than 1.0 for
* interpolators which overshoot their targets, or less than 0 for
* interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}
由上面的代碼可以清楚的看到一點,Interpolator 只是繼承于 TimeInterpolator ,里面只是一個空實現而已。而在 TimeInterpolator 下,也只有 float getInterpolation(float input); 一個方法。input 是一個 0.0 ~ 1.0 的值 , 經過自定義的方法 ,那么只要返回適當的值,那么就能實現各種的效果。
例如下面是系統實現的先加速后減速的Interpolator。
AccelerateDecelerateInterpolator
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
當然Android SDK 中已經實現了幾個 Interpolator 讓開發者直接使用。
下面繼續介紹動畫,補間動畫和逐幀動畫一樣,既能使用XML實現也能使用Code實現。
XML的文件應放置在 res/anim 目錄上。
透明度變化 Alpha
XML
anim_tween_alpha.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
>
<alpha
android:repeatMode="reverse"
android:repeatCount="-1"
android:duration="1000"
android:fromAlpha="0"
android:toAlpha="1" />
</set>
android:interpolator 用來指定插值器
android:repeatMode 重復的模式
android:repeatCount="-1" 重復的次數。 -1 為無限循環。
XML寫完了,就要在代碼中使用他了。
ImageView ivTweenXml = (ImageView) findViewById(R.id.iv_tween_xml);
AnimationSet alphaSet = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_alpha);
ivTweenXml.startAnimation(alphaSet);
Code
ImageView ivTweenCode = (ImageView) findViewById(R.id.iv_tween_code);
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
alphaAnimation.setRepeatMode(Animation.REVERSE);
alphaAnimation.setRepeatCount(-1);
ivTweenCode.startAnimation(alphaAnimation);
上面都實現了透明度從0到1.
縮放變化 Scale
XML
anim_tween_scale.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<scale
android:duration="1000"
android:fromXScale="0.2"
android:fromYScale="0.2"
android:toXScale="1"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="reverse"
/>
</set>
ImageView ivScaleXml = (ImageView) findViewById(R.id.iv_scale_xml);
AnimationSet scaleSet = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_scale);
ivScaleXml.startAnimation(scaleSet);
pivotX 中心點
直接寫數字代表 控件本身的坐標系中的x的值
數字后面加了 % 例如 :50% ,代表 在本身的坐標系中的 x軸長度的50%
Code
ImageView ivScaleCode = (ImageView) findViewById(R.id.iv_scale_code);
ScaleAnimation scaleAnimation = new ScaleAnimation(0.2f, 1, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(1000);
scaleAnimation.setRepeatMode(Animation.REVERSE);
scaleAnimation.setRepeatCount(-1);
ivScaleCode.startAnimation(scaleAnimation);
位移變化 Translate
XML
anim_tween_translate.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<translate
android:duration="1000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100"
android:toYDelta="0"
android:repeatCount="-1"
android:repeatMode="reverse"
/>
</set>
ImageView ivTranslateXml = (ImageView) findViewById(R.id.iv_translate_xml);
AnimationSet translateSet = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_translate);
ivTranslateXml.startAnimation(translateSet);
Code
ImageView ivTranslateCode = (ImageView) findViewById(R.id.iv_translate_code);
TranslateAnimation translateAnimation = new TranslateAnimation( 0,100,0,0);
translateAnimation.setDuration(1000);
translateAnimation.setRepeatMode(Animation.REVERSE);
translateAnimation.setRepeatCount(-1);
ivTranslateCode.startAnimation(translateAnimation);
旋轉變化 Rotate
XML
anim_tween_rotate.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<rotate
android:duration="1000"
android:fromDegrees="0"
android:toDegrees="360"
android:toXScale="1"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="reverse"
/>
</set>
ImageView ivRotateXml = (ImageView) findViewById(R.id.iv_rotate_xml);
AnimationSet rotateSet = (AnimationSet) AnimationUtils.loadAnimati(TweenActivity.this,R.anim.anim_tween_rotate);
ivRotateXml.startAnimation(rotateSet);
Code
ImageView ivRotateCode = (ImageView) findViewById(R.id.iv_rotate_code);
RotateAnimation rotateAnimation = new RotateAnimation( 0,360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(1000);
rotateAnimation.setRepeatMode(Animation.REVERSE);
rotateAnimation.setRepeatCount(-1);
ivRotateCode.startAnimation(rotateAnimation);
組合起來
上面顯示的就是每一種效果各自實現的方法,現在我們可以讓這些效果組合起來。
xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
>
<alpha
android:duration="1000"
android:fromAlpha="0"
android:repeatCount="-1"
android:repeatMode="reverse"
android:toAlpha="1" />
<rotate
android:duration="1000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="reverse"
android:toDegrees="360"
android:toXScale="1"
android:toYScale="1" />
<scale
android:duration="1000"
android:fromXScale="0.2"
android:fromYScale="0.2"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:repeatMode="reverse"
android:toXScale="1"
android:toYScale="1" />
<translate
android:duration="1000"
android:fromXDelta="0"
android:fromYDelta="0"
android:repeatCount="-1"
android:repeatMode="reverse"
android:toXDelta="100"
android:toYDelta="0" />
</set>
ImageView ivTogetherXml = (ImageView) findViewById(R.id.iv_together_xml);
AnimationSet togetherSet = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_together);
ivTogetherXml.startAnimation(togetherSet);
Code
ImageView ivTogetherCode = (ImageView) findViewById(R.id.iv_together_code);
AnimationSet animationSet = new AnimationSet(false);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(scaleAnimation);
ivTogetherCode.startAnimation(animationSet);
效果如圖所示:
監聽
播放動畫效果的時候我們可以做到對動畫開始、結束、重復的監聽。
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//動畫開始時調用
}
@Override
public void onAnimationEnd(Animation animation) {
//動畫結束時調用
}
@Override
public void onAnimationRepeat(Animation animation) {
//動畫重復時調用
}
});
只要在對應的位置添加自己想要的效果,那么就可以實現了。
AccelerateInterpolator 加速,開始時慢中間加速
幾種自帶的動畫插入器
DecelerateInterpolator 減速,開始時快然后減速
AccelerateDecelerateInterolator 先加速后減速,開始結束時慢,中間加速
AnticipateInterpolator 反向,先向相反方向改變一段再加速播放
AnticipateOvershootInterpolator 反向加超越,先向相反方向改變,再加速播放,會超出目的值然后緩慢移動至目的值
BounceInterpolator 跳躍,快到目的值時值會跳躍,如目的值100,后面的值可能依次為85,77,70,80,90,100
CycleIinterpolator 循環,動畫循環一定次數,值的改變為一正弦函數:Math.sin(2* mCycles* Math.PI* input)
LinearInterpolator 線性,線性均勻改變
OvershootInterpolator超越,最后超出目的值然后緩慢改變到目的值