一 動畫的分類
在Android動畫中,總共有兩種類型的動畫View Animation(視圖動畫)和Property Animator(屬性動畫)。
- 視圖動畫包括Tween Animation(補間動畫)和Frame
Animation(逐幀動畫)。Tween 動畫可以使視圖組件移動、縮放,旋轉以及產生透明度的變化;Frame動畫就是將一個完整的動畫拆分成一張張單獨的圖片,然後再順序的播放這些排列好的圖片,類似於動畫片的工作原理。 - 屬性動畫包括ValueAnimator和ObjectAnimator
二 屬性動畫和其他動畫的區別
第一點從直觀上看,他們有如下三點不同:
- 引入時間不同:View Animation是API Level 1就引入的。Property Animation是API Level 11引入的,即Android 3.0纔開始有Property Animation相關的API。
- 所在包名不同:View Animation在包android.view.animation中。而Property Animation API在包 android.animation中。
- 動畫類的命名不同:View Animation中動畫類取名都叫XXXXAnimation,而在Property Animator中動畫類的取名則叫XXXXAnimator
大家都知道逐幀動畫主要是用來實現動畫的,而補間動畫才能實現控件的漸入漸出、移動、旋轉和縮放的;而Property Animator是在Android 3.0版本才引入的,之前是沒有的。大家可能會覺得補間動畫和逐幀動畫已經很全了,爲什麼還要引入Property Animator呢?
我提出一個假設:請問大家,如何利用補間動畫來將一個控件的背景色在一分鐘內從綠色變爲紅色?這個效果想必沒辦法僅僅通過改變控件的漸入漸出、移動、旋轉和縮放來實現吧,而這個效果是可以通過Property Animator完美實現的
這就是第一個原因:Property Animator能實現補間動畫無法實現的功能
大家都知道,補間動畫和逐幀動畫統稱爲View Animation,也就是說這兩個動畫只能對派生自View的控件實例起作用;而Property Animator則不同,從名字中可以看出屬性動畫,應該是作用於控件屬性的!正因爲屬性動畫能夠只針對控件的某一個屬性來做動畫,所以也就造就了他能單獨改變控件的某一個屬性的值!比如顏色!這就是Property Animator能實現補間動畫無法實現的功能的最重要原因。
- 因此我們得到了第二點不同:View Animation僅能對指定的控件做動畫,而Property Animator是通過改變控件某一屬性值來做動畫的。
假設我們將一個按鈕從左上角利用補間動畫將其移動到右下角,在移動過程中和移動後,這個按鈕都是不會響應點擊事件的。這是爲什麼呢?因爲補間動畫僅僅轉變的是控件的顯示位置而已,並沒有改變控件本身的值。View Animation的動畫實現是通過其Parent View實現的,在View被drawn時Parents View改變它的繪製參數,這樣雖然View的大小或旋轉角度等改變了,但View的實際屬性沒變,所以有效區域還是應用動畫之前的區域;我們看到的效果僅僅是系統作用在按鈕上的顯示效果,利用動畫把按鈕從原來的位置移到了右下角,但按鈕內部的任何值是沒有變化的,所以按鈕所捕捉的點擊區域仍是原來的點擊區域。
- 這就得到了第三點不同:補間動畫雖能對控件做動畫,但並沒有改變控件內部的屬性值。這也是視圖動畫的一個非常大的缺點:不具備交互性,當某個元素髮生視圖動畫後,其響應事件的位置依然在動畫前的位置。而Property Animator則是恰恰相反,Property Animator是通過改變控件內部的屬性值來達到動畫效果的。
三 動畫的使用
幀動畫實現wifi信號跳動
1.首先在res/drawabl目錄下創建一個幀動畫的的xml文件
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/icon1" android:duration="200"></item>
<item android:drawable="@drawable/icon2" android:duration="200"></item>
<item android:drawable="@drawable/icon3" android:duration="200"></item>
<item android:drawable="@drawable/icon4" android:duration="200"></item>
<item android:drawable="@drawable/icon5" android:duration="200"></item>
<item android:drawable="@drawable/icon6" android:duration="200"></item>
</animation-list>
2.給ImageView設置幀動畫
<ImageView
android:id="@+id/iv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/frame_anim"
/>
3.獲取AnimationDrawable類,執行開始方法
public class MainActivity extends AppCompatActivity {
private ImageView mImageView;
private AnimationDrawable mAnimationDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_show);
}
public void start(View view){
//通過ImageView獲取到幀動畫的核心類
mAnimationDrawable = (AnimationDrawable) mImageView.getDrawable();
mAnimationDrawable.start();//一旦開始了就不會自動停止,就算設置成了只播放一次
}
public void stop(View view){
if (mAnimationDrawable.isRunning()) {
mAnimationDrawable.stop();//手動停止動畫
}
}
}
補間動畫
作用在任意view控件,有透明,平移,縮放,旋轉四種效果,當然也可以使用動畫集合,這些效果都可以通過代碼和xml文件兩種方式實現。
1.代碼動態實現
public void alpha(View view) {
/*
* 從一個透明度到另外一個透明度 範圍【0,1】 1.0 代表完全不透明,就是完全可見 0.0代表完全透明,就是完全不可見
*/
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
// 設置時間
alphaAnimation.setDuration(100);// 毫秒 動畫的時長
// iv.setAnimation(alphaAnimation);//將動畫設置給控件
//
// alphaAnimation.start();//啓動動畫 //這兩行代碼不兼容Android4.4
// 重複無限次
alphaAnimation.setRepeatCount(Animation.INFINITE);
alphaAnimation.setRepeatMode(Animation.REVERSE);// 設置重複的策略,逆向
iv.startAnimation(alphaAnimation);// 兼容性強
}
public void translate(View view) {
/*
* 參數1:x方向的參照物
*/
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0.7f, Animation.RELATIVE_TO_SELF, 0, AlphaAnimation.RELATIVE_TO_SELF, 0);
translateAnimation.setDuration(5000);
translateAnimation.setRepeatMode(Animation.REVERSE);
translateAnimation.setRepeatCount(Animation.INFINITE);
// iv.startAnimation(translateAnimation);
rootView.startAnimation(translateAnimation);
}
public void scale(View view) {
ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 15f, 0.5f, 15, Animation.RELATIVE_TO_SELF, 0.45f, Animation.RELATIVE_TO_SELF, 0.32f);
scaleAnimation.setDuration(1000);
scaleAnimation.setRepeatCount(9);
iv.startAnimation(scaleAnimation);
}
public void rotate(View view) {
// RotateAnimation rotateAnimation = new RotateAnimation(-45, 45,
// Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1);
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(10000);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.REVERSE);
iv.startAnimation(rotateAnimation);
}
public void set(View view) {
//1. 創建個動畫集合
AnimationSet animationSet = new AnimationSet(false);
//2. 創建我們想要的動畫對象
ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 15f, 0.5f, 15, Animation.RELATIVE_TO_SELF, 0.45f, Animation.RELATIVE_TO_SELF, 0.32f);
scaleAnimation.setDuration(1000);
scaleAnimation.setRepeatCount(9);
//2. 創建我們想要的動畫對象
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(1000);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
//3. 將動畫添加到動畫集合對象中
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(rotateAnimation);
//4. 執行動畫
iv.startAnimation(animationSet);
}
2.xml文件實現(有利於複用)
- 平移動畫
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0" // 開始的x座標
android:fromYDelta="0" // 開始的y座標
android:toXDelta="100" // 結束的x座標
android:toYDelta="100" // 結束的y座標
android:duration="500" // 動畫執行時長 單位 毫秒
android:repeatCount="3"// 重複次數
android:repeatMode="reverse" // 重複模式 reverse反轉restart重啓
android:fillAfter="true" // 是否停留在動畫結束時
>
</translate>
- 縮放動畫
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.5" // 開始x方向縮放比例
android:fromYScale="0.5" // 開始y方向縮放比例
android:toXScale="1.5" // 結束x方向縮放比例
android:toYScale="1.5" // 結束y方向縮放比例
android:duration="500"
android:repeatCount="3"
android:repeatMode="reverse"
android:pivotX="50%" // x縮放中心 帶p表示相對於parent父控件
android:pivotY="50%" // y縮放中心 帶p表示相對於parent父控件
>
</scale>
- 旋轉動畫
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0" // 開始旋轉角度
android:toDegrees="180" // 結束旋轉角度
android:pivotX="50%"
android:pivotY="50%"
android:duration="500"
android:repeatCount="3"
android:repeatMode="reverse" >
</rotate>
- 透明度動畫
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1.0" // 開始透明度
android:toAlpha="0.3" // 結束透明度
android:repeatCount="3"
android:repeatMode="reverse"
android:duration="500" >
</alpha>
- 組合動畫
<set>
...
</set>
在代碼中將動畫的xml轉換爲Animation對象
public void alpha2(View view) {
// 將動畫的xml轉換爲Animation對象
AlphaAnimation animation = (AlphaAnimation) AnimationUtils.loadAnimation(this, R.anim.alpha_anim);
animation.setFillAfter(true);// 讓動畫執行完後保持執行完後的效果
iv.startAnimation(animation);
}
屬性動畫
1.代碼實現
// 旋轉動畫
// 參數 >> 執行動畫的控件, 屬性名稱, 屬性值
ObjectAnimator ra = ObjectAnimator.ofFloat(iv_image, "rotation", 180f);
ra.setRepeatCount(3); // ValueAnimator.INFINITE 無限
ra.setRepeatMode(ValueAnimator.REVERSE);
ra.setDuration(500);
ra.start();
2.通過xml文件實現AnimatorInflater
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="translationX" // 屬性名稱
android:duration="500" // 執行時長
android:repeatCount="3" // 重複次數, infinite無限
android:repeatMode="reverse"// 重複模式 restart重啓, reverse反轉
android:valueType="floatType"// 值類型
android:valueFrom="-50" // 開始值
android:valueTo="100" // 結束值
>
</objectAnimator>
3.動畫集合
// 動畫集合
AnimatorSet set = new AnimatorSet();
// set.playTogether(ta, sa, ra, aa); // 一起播放
// set.playSequentially(ta, sa, ra, aa); // 按先後順序播放
// 平移同時縮放, 在旋轉之前, 在透明度之後
set.play(ta).with(sa).before(ra).after(aa); // 透明度 -> 平移同時縮放 -> 旋轉
set.setStartDelay(1000); // 動畫開始延時時間
set.start(); // 開始
,