第七章Android動畫機制與使用技巧(Android群英傳)


學習本章將瞭解:


Android視圖動畫

Android屬性動畫

Android動畫實例


7.1、Android View動畫框架


Animation框架定義瞭透明度、旋轉、縮放、位移幾種常見的動畫,而且控制的是整個View。


原理是:


1、每次繪制時View所在的ViewGroup中的drawChild函數獲取該view的Animation的Transformation值

2、調用canvas.concat通過運算完成動畫幀

3、如果動畫沒有完成就繼續調用invalidate反復繪制。


7.1.1、視圖動畫:


優點:效率高,使用方便

缺點:隻能做普通動畫,避免交互動畫

視圖動畫提供瞭:


AlphaAnimation:透明度動畫
RotateAnimation:旋轉動畫
TranslateAnimation:位移動畫
ScaleAnimation:縮放動畫

7.1.2、動畫集合AnimationSet,可以將動畫以組合的形式展現出來


示例代碼如下:


package com.imooc.viewanim;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void btnAlpha(View view) {
AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
view.startAnimation(aa);
}

public void btnRotate(View view) {
RotateAnimation ra = new RotateAnimation(0, 360, 100, 100);
ra.setDuration(1000);
view.startAnimation(ra);
}

public void btnRotateSelf(View view) {
RotateAnimation ra = new RotateAnimation(0, 360,
RotateAnimation.RELATIVE_TO_SELF, 0.5F,
RotateAnimation.RELATIVE_TO_SELF, 0.5F);
ra.setDuration(1000);
view.startAnimation(ra);
}

public void btnTranslate(View view) {
TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
ta.setDuration(1000);
view.startAnimation(ta);
}

public void btnScale(View view) {
ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2);
sa.setDuration(1000);
view.startAnimation(sa);
}

public void btnScaleSelf(View view) {
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1,
Animation.RELATIVE_TO_SELF, 0.5F,
Animation.RELATIVE_TO_SELF, 0.5F);
sa.setDuration(1000);
view.startAnimation(sa);
}

public void btnSet(View view) {
AnimationSet as = new AnimationSet(true);
as.setDuration(1000);

AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
as.addAnimation(aa);

TranslateAnimation ta = new TranslateAnimation(0, 100, 0, 200);
ta.setDuration(1000);
as.addAnimation(ta);

view.startAnimation(as);
}

}

對於動畫事件Andorid也提供瞭回調


代碼如下:


ScaleAnimation sa;//任意一個動畫類型
sa.setAnimationListener(new Animation.AnimationListener() {
//動畫開發
@Override
public void onAnimationStart(Animation animation) {

}
//結束
@Override
public void onAnimationEnd(Animation animation) {

}
//重復
@Override
public void onAnimationRepeat(Animation animation) {

}
});

通過前面的實例,可以發現視圖動畫的效果比較局限,註定會被更豐富的動畫所取代


7.2、Andorid屬性動畫分析


3.0之前已有Animation動畫框架,但是有局限性,隻能顯示,不能響應事件

所以3.0之後,google就提出瞭屬性動畫


7.2.1、ObjectAnimator


以前的動畫框架,不能改變事件的位置(按鈕移動走瞭,點擊事件還在移動前的位置)

而屬性動畫可以改變事件的位置


ObjectAnimator animator0 = ObjectAnimator.ofFloat(
mImageViews.get(0),
"alpha",
1F,
0.5F);

第一個參數:需要操控的view

第二個參數:需要操控的屬性

最後一個參數:變化的值

註意:在使用ObjectAnimator的時候,操控的屬性必須具有get,set方法,不然ObjectAnimator不起效


7.2.2、PropertyValuesHolder


類似視圖動畫中的AnimationSet,多種動畫同時進行


7.2.3、ValueAnimator


它是屬性動畫的核心,ObjectAnimator繼承自ValueAnimator

通常情況下我們在ValueAnimator中AnimatorUpdateListener監聽數值的變換,完成動畫的變換


7.2.4、動畫的監聽


一個完整的動畫有:start、end、repeat、cancel的過程

1、監聽所有事件:

代碼如下:


ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0),
"alpha", 0.5F, 1F);
animator0.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) {

}
});

2、監聽指定事件:


animator0.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});

7.2.5、AnimatorSet


類似PropertyValuesHolder和視圖動畫中的AnimationSet,多種動畫同時進行,同時也能控制播放順序。


拓展:


android AnimatorSet AnimationSet 的區別


AnimatorSet 和 AnimationSet 都是動畫集合。這裡簡單介紹下他們的異同,瞭解這些後在設計動畫實現時才能得心應手。

AnimationSet 我們最常用的是調用其 addAnimation 將一個個不一樣的動畫組織到一起來,然後調用view 的 startAnimation 方法觸發這些動畫執行。功能較弱不能做到把集合中的動畫按一定順序進行組織然後在執行的定制。

AnimatorSet 我們最常用的是調用其play、before、with、after 等方法設置動畫的執行順序,然後調用其start 觸發動畫執行。

AnimationSet 與 AnimatorSet 最大的不同在於,AnimationSet 使用的是 Animation 子類、AnimatorSet 使用的是 Animator 的子類。

Animation 是針對視圖外觀的動畫實現,動畫被應用時外觀改變但視圖的觸發點不會發生變化,還是在原來定義的位置。

Animator 是針對視圖屬性的動畫實現,動畫被應用時對象屬性產生變化,最終導致視圖外觀變化。


7.2.6、在XML中使用屬性動畫


屬性動畫和視圖動畫一樣,可以直接寫在xml中


<objectAnimator
android:propertyName="alpha"android:duration="500"android:valueTo="1f"/>

Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.anim.an_test);
animator.setTarget("");
animator.start();

7.2.7、View的animate方法


Android 3.0之後,google給View增加瞭animate方法來直接驅動屬性動畫,是屬性動畫的一種簡寫方式

基本用法如下:


View v = null;
v.animate().alpha(0).setDuration(100).start();

7.3、Andorid佈局動畫


佈局動畫是作用在ViewGroup上,給ViewGroup增加View的時候,添加一個動畫的過渡效果。

最簡單的佈局動畫是在ViewGroup的XML中,添加下面的屬性打開佈局動畫。


android:animateLayoutChanges="true"  

也可以使用LayoutAnimationController來自定義一個過渡動畫


7.4、插值器


interpolators:控制動畫的速度


7.5、自定義動畫


創建自定義動畫非常簡單,隻需要實現它的applyTransformation的邏輯就可以瞭。通常情況下還需要覆蓋父類的initialize方法實現初始化的一些工作。


7.6、Android 5.x SVG矢量動畫機制


Google在Andorid5.x中增加瞭對矢量圖形的支持

Google在Andorid5.x中提供瞭2個新的api來支持SVG

VectorDrawable——創建基於xml的SVG圖形

AnimatedVectorDrawable——實現動畫效果

具體用法可參考:

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0825/3362.html


7.7、Android 動畫特效


下面我們做個實例:


package com.imooc.anim;

import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class PropertyTest extends Activity implements View.OnClickListener {

private int[] mRes = {R.id.imageView_a, R.id.imageView_b, R.id.imageView_c,
R.id.imageView_d, R.id.imageView_e};
private List<ImageView> mImageViews = new ArrayList<ImageView>();
private boolean mFlag = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.property);
for (int i = 0; i < mRes.length; i++) {
ImageView imageView = (ImageView) findViewById(mRes[i]);
imageView.setOnClickListener(this);
mImageViews.add(imageView);
}
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageView_a:
if (mFlag) {
startAnim();
} else {
closeAnim();
}
break;
default:
Toast.makeText(PropertyTest.this, "" + v.getId(),
Toast.LENGTH_SHORT).show();
break;
}
}

private void closeAnim() {

ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0),
"alpha", 0.5F, 1F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageViews.get(1),
"translationY", 200F, 0);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageViews.get(2),
"translationX", 200F, 0);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageViews.get(3),
"translationY", -200F, 0);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImageViews.get(4),
"translationX", -200F, 0);
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.setInterpolator(new BounceInterpolator());
set.playTogether(animator0, animator1, animator2, animator3, animator4);
set.start();
mFlag = true;
}

private void startAnim() {
ObjectAnimator animator0 = ObjectAnimator.ofFloat(
mImageViews.get(0),
"alpha",
1F,
0.5F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(
mImageViews.get(1),
"translationY",
200F);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(
mImageViews.get(2),
"translationX",
200F);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(
mImageViews.get(3),
"translationY",
-200F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(
mImageViews.get(4),
"translationX",
-200F);
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.setInterpolator(new BounceInterpolator());
set.playTogether(
animator0,
animator1,
animator2,
animator3,
animator4);
set.start();
mFlag = false;
}
}

7.7.2、計時器動畫


package com.imooc.anim;

import android.animation.ValueAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class TimerTest extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timer);
View v = null;
v.animate().alpha(0).setDuration(100).start();
}

public void tvTimer(final View view) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
valueAnimator.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
((TextView) view).setText("$ " +
(Integer) animation.getAnimatedValue());
}
});
valueAnimator.setDuration(3000);
valueAnimator.start();
}
}

0 個評論

要回覆文章請先登錄註冊