Android動(dòng)畫 1:視圖動(dòng)畫(Tween Animation)、屬性動(dòng)畫

1睡陪、視圖動(dòng)畫Animation (Tween Animation)

通過不斷的對(duì)view對(duì)象做圖像變換(漸變寺渗、平移匿情、縮放、旋轉(zhuǎn))而產(chǎn)生動(dòng)畫效果信殊,這種動(dòng)畫只適用于View對(duì)象炬称。
1、AlphaAnimation

AlphaAnimation(float fromAlpha, float toAlpha)

其中涡拘,1:不透明玲躯;0:透明

2、RotateAnimation

RotateAnimation(float fromDegrees, float toDegrees)
---
RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY)
---
RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

注意:

  • 旋轉(zhuǎn)的中心點(diǎn)鳄乏,默認(rèn)是view的左上角跷车;
  • pivotX、pivotY汞窗,是旋轉(zhuǎn)的中心點(diǎn)的偏移量姓赤;
  • pivotXType的取值可以是RELATIVE_TO_PARENT、RELATIVE_TO_SELF仲吏,代表的是中心點(diǎn)(默認(rèn)是view的左上角)偏移量大小的取值是相對(duì)于自身還是相對(duì)于parent不铆,最終都是相對(duì)于view的左上角進(jìn)行偏移。
RotateAnimation(0,360,300,300)
RotateAnimation(0,360,RotateAnimation.RELATIVE_TO_PARENT,0.5f,RotateAnimation.RELATIVE_TO_PARENT,0.5f)

即旋轉(zhuǎn)中心點(diǎn)從view的左上角裹唆,偏移到了右下角(相對(duì)于parent50%的地方)

RotateAnimation(0,360,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f)

3誓斥、TranslateAnimation

TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
---
TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
        int fromYType, float fromYValue, int toYType, float toYValue) 

4、ScaleAnimation

ScaleAnimation(float fromX, float toX, float fromY, float toY)
---
ScaleAnimation(float fromX, float toX, float fromY, float toY, 
       float pivotX, float pivotY) 
---
ScaleAnimation(float fromX, float toX, float fromY, float toY,
        int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

相對(duì)于某個(gè)中心點(diǎn)縮放许帐,和RotateAnimation類似

ScaleAnimation(1,0,1,0,ScaleAnimation.RELATIVE_TO_PARENT,0.2f,ScaleAnimation.RELATIVE_TO_PARENT,0.2f)

代碼如下:

    //透明動(dòng)畫效果
    AlphaAnimation alphaAnimation=new AlphaAnimation(0,1);
    alphaAnimation.setDuration(1000);
    view.startAnimation(alphaAnimation);

---

    //旋轉(zhuǎn)動(dòng)畫效果
    RotateAnimation rotateAnimation=new RotateAnimation(0,360,RotateAnimation.RELATIVE_TO_PARENT,0.1f,
                        RotateAnimation.RELATIVE_TO_PARENT,0.1f);
    rotateAnimation.setDuration(1000);
    v.startAnimation(rotateAnimation);

---

    //平移動(dòng)畫效果
    TranslateAnimation translateAnimation=new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT,0,
            TranslateAnimation.RELATIVE_TO_PARENT,0.2f,
            TranslateAnimation.RELATIVE_TO_PARENT,0,
            TranslateAnimation.RELATIVE_TO_PARENT,0.2f);
    translateAnimation.setDuration(1000);
    v.startAnimation(translateAnimation);

---

    //縮放動(dòng)畫效果
    ScaleAnimation scaleAnimation=new ScaleAnimation(1,0,1,0,ScaleAnimation.RELATIVE_TO_PARENT,0.2f,
                    ScaleAnimation.RELATIVE_TO_PARENT,0.2f);
    scaleAnimation.setDuration(2000);
    v.startAnimation(scaleAnimation);   
---

 v.startAnimation(AnimationUtils.loadAnimation(this,R.anim.rotate));

    //透明動(dòng)畫效果
    <alpha android:duration="1000"
        android:fromAlpha="1"
        android:toAlpha="0"/>

--- 

    //旋轉(zhuǎn)動(dòng)畫效果
    <rotate android:duration="1000"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:pivotX="50%"
        android:pivotY="50%"/>

---

    //平移動(dòng)畫效果
    <translate android:duration="1000"
        android:fromXDelta="0"
        android:toXDelta="20%p"
        android:fromYDelta="0"
        android:toYDelta="30%p"/>

注意:

  • num%劳坑、num%p表示相對(duì)于自身或者父控件,跟RELATIVE_TO_PARENT成畦、RELATIVE_TO_SELF效果類似距芬;如果以浮點(diǎn)數(shù)字表示,是一個(gè)絕對(duì)值循帐,代表相對(duì)自身原始位置的像素值框仔;
  • RepeatMode:
    Animation.RESTART,表示動(dòng)畫重新從頭開始執(zhí)行拄养,當(dāng)一次動(dòng)畫執(zhí)行結(jié)束之后离斩,圖片將重新從頭開始執(zhí)行。
    Animation.REVERSE瘪匿,表示動(dòng)畫反方向執(zhí)行跛梗,當(dāng)一次動(dòng)畫執(zhí)行結(jié)束之后,圖片將向反方向運(yùn)動(dòng)棋弥。
  • RepeatCount:動(dòng)畫的重復(fù)次數(shù)核偿,Animation.INFINITE 無限循環(huán)
  • fillBefore:動(dòng)畫結(jié)束時(shí)畫面停留在此動(dòng)畫的第一幀
    fillAfter:動(dòng)畫結(jié)束是畫面停留在此動(dòng)畫的最后一幀
  • 加載xml文件中的動(dòng)畫
    AnimationUtils類調(diào)用loadAnimation(context, id)方法來加載xml文件

5、可以通過AnimationSet顽染,將動(dòng)畫以組合的形式展示

        AnimationSet animationSet=new AnimationSet(true);
        animationSet.setDuration(2000);

        ScaleAnimation scaleAnimation=new ScaleAnimation(1,0,1,0,ScaleAnimation.RELATIVE_TO_PARENT,0.2f,
              ScaleAnimation.RELATIVE_TO_PARENT,0.2f);
        scaleAnimation.setDuration(2000);
        animationSet.addAnimation(scaleAnimation);

        ...

        v.startAnimation(animationSet);
AnimationSet

6宪祥、自定義動(dòng)畫
實(shí)現(xiàn)Animation 接口的applyTransformation()方法聂薪,還可以覆蓋initialize()方法,做一些初始化的操作

public class ReversalAnimation extends Animation {
    private int height;
    private int width;

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(1000);
        setInterpolator(new CycleInterpolator(0.25f));
        this.height = height * 2;
        this.width = width;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        Matrix matrix = t.getMatrix();
        matrix.preScale(1 - (float) Math.sin((interpolatedTime) * Math.PI), 1, width / 2, 0);
        matrix.preTranslate(0, -(float) Math.sin(interpolatedTime * Math.PI) * height);
    }
}

其中interpolatedTime的取值為0~1蝗羊,0標(biāo)識(shí)動(dòng)畫開始執(zhí)行藏澳,1標(biāo)識(shí)動(dòng)畫執(zhí)行完了
Transformation,可以通過它獲得當(dāng)前矩陣對(duì)象matrix耀找,通過matrix將動(dòng)畫效果執(zhí)行出來

自定義動(dòng)畫

7翔悠、插值器
如下

8、監(jiān)聽器
可以設(shè)置AnimationListener野芒,獲取動(dòng)畫開始蓄愁、結(jié)束、重復(fù)事件

    translateAnimation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            Toast.makeText(Main2Activity.this,"onAnimationStart",Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            Toast.makeText(Main2Activity.this,"onAnimationEnd",Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

9狞悲、執(zhí)行動(dòng)畫
通過view的startAnimation

但是視圖動(dòng)畫不具備交互性撮抓,在縮放和平移一個(gè)View的時(shí)候,并沒有改變控件內(nèi)部的屬性值摇锋,它的有效點(diǎn)擊區(qū)域丹拯,依然保持原來的大小和位置,如圖在動(dòng)畫的結(jié)束位置點(diǎn)擊荸恕,是沒有效果的乖酬,只有在原始位置(矩形區(qū)域),點(diǎn)擊才有效果

視圖動(dòng)畫

參考:Android 動(dòng)畫學(xué)習(xí) View Animation

2融求、屬性動(dòng)畫Animator

在Android3.0(level 11)引入的咬像,通過動(dòng)態(tài)地改變對(duì)象的屬性值而達(dá)到動(dòng)畫效果缘厢,可以為任何的對(duì)象添加動(dòng)畫(當(dāng)然也包括View在內(nèi))征候。
屬性動(dòng)畫改變了View的屬性,比如對(duì)于View的最終位置x=left+translationX棍弄,所以在最終位置就可以響應(yīng)點(diǎn)擊事件陷舅;

Property Animation的工作流程

1倒彰、ValueAnimator

ValueAnimator本身不提供任何的動(dòng)畫效果,它可以產(chǎn)生有一定規(guī)律的數(shù)字蔑赘,可以在AnimatorUpdateListener中監(jiān)聽這些數(shù)字的變化狸驳,從而完成動(dòng)畫效果

ValueAnimator動(dòng)畫的整個(gè)過程

ValueAnimator動(dòng)畫的整個(gè)過程如下:
(0)预明、 ofInt(0,400)表示指定動(dòng)畫的數(shù)字區(qū)間缩赛,是從0運(yùn)動(dòng)到400;
(1)撰糠、 在動(dòng)畫過程中酥馍, Animator會(huì)根據(jù)動(dòng)畫總時(shí)間和已進(jìn)行的時(shí)間自動(dòng)計(jì)算出一個(gè)時(shí)間比例因子,大小介于0和1之間阅酪,0表示開始旨袒。

時(shí)間比例因子 = 當(dāng)前已進(jìn)行的時(shí)間/動(dòng)畫執(zhí)行的總時(shí)間

(2)汁针、Interpolator(差值器/加速器):Animator會(huì)根據(jù)時(shí)間比例因子,返回當(dāng)前動(dòng)畫進(jìn)度所對(duì)應(yīng)的數(shù)字進(jìn)度:這個(gè)數(shù)字進(jìn)度是百分制的砚尽,以小數(shù)表示施无。

publicinterfaceTimeInterpolator{
floatgetInterpolation(floatinput);
}

但是我們通過監(jiān)聽器拿到的是當(dāng)前動(dòng)畫所對(duì)應(yīng)的具體數(shù)值,而不是百分制的進(jìn)度必孤。那么就必須有一個(gè)地方會(huì)根據(jù)當(dāng)前的數(shù)字進(jìn)度猾骡,將其轉(zhuǎn)化為對(duì)應(yīng)的數(shù)值,這個(gè)地方就是Evaluator敷搪;
(3)兴想、 Evaluator:Evaluator將從加速器返回的數(shù)字進(jìn)度轉(zhuǎn)成對(duì)應(yīng)的數(shù)字值。

publicinterfaceTypeEvaluator<T>{
T  evaluate(floatfraction,T startValue,T endValue)
}

(4)赡勘、 監(jiān)聽器:通過在AnimatorUpdateListener監(jiān)聽器使用animation.getAnimatedValue()函數(shù)拿到Evaluator中返回的數(shù)字值嫂便,為需要執(zhí)行動(dòng)畫的對(duì)象設(shè)置對(duì)應(yīng)屬性的屬性值。onAnimationUpdate()在動(dòng)畫每播放一幀時(shí)都會(huì)調(diào)用闸与。

動(dòng)畫在的整個(gè)過程中毙替,會(huì)根據(jù)我們當(dāng)初設(shè)置的TimeInterpolator 和TypeEvaluator的計(jì)算方式計(jì)算出的不同的屬性值,從而不斷地改變對(duì)象屬性值的大小几迄,進(jìn)而產(chǎn)生各式各樣的動(dòng)畫效果蔚龙。

創(chuàng)建ValueAnimator的常用方法如下:

  • ValueAnimator ofInt(int... values)
  • ValueAnimator ofArgb(int... values)
  • ValueAnimator ofFloat(float... values)
  • ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)

這些方法都有默認(rèn)的加速器和Evaluator,不指定則使用默認(rèn)的映胁;
其中ofInt()的默認(rèn)Evaluator是IntEvaluator木羹,ofFloat是FloatEvalutor,ofArgb是ArgbEvaluator解孙;
參數(shù)的類型是定值

代碼如下:

    ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,1);
    valueAnimator.setTarget(v);
    valueAnimator.setDuration(1000);
    valueAnimator.start();
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float timeAnim= (float) animation.getAnimatedValue();
            if(timeAnim<0.4f){
                imageView.setTranslationY(-1000*timeAnim);
            }else if(timeAnim>=0.4f && timeAnim<=0.8f){
                imageView.setScaleX((float) Math.abs((timeAnim-0.6)/0.2));
            }else {
                imageView.setTranslationY(-1000*(1-timeAnim));
            }
        }
    });
屬性動(dòng)畫4.gif
  • ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)
    ofInt()只能傳入Integer類型的值坑填,而ofFloat()只能傳入Float類型的值。如果我們需要操作其它類型的變量弛姜,可以使用以上方法

TypeEvaluator

public class PointXYEvaluator implements TypeEvaluator<PointXY> {
    @Override
    public PointXY evaluate(float fraction, PointXY startValue, PointXY endValue) {
        int pointX= (int) (startValue.getPointX()+(endValue.getPointX()-startValue.getPointX())*fraction);
        int pointy= (int) (startValue.getPointY()+(endValue.getPointY()-startValue.getPointY())*fraction);
        return new PointXY(pointX,pointy);
    }
}

自定義參數(shù)類型

public class PointXY {
    private int pointX;
    private int pointY;

    public PointXY(int pointX, int pointY) {
        this.pointX = pointX;
        this.pointY = pointY;
    }

    public int getPointX() {
        return pointX;
    }

    public void setPointX(int pointX) {
        this.pointX = pointX;
    }

    public int getPointY() {
        return pointY;
    }

    public void setPointY(int pointY) {
        this.pointY = pointY;
    }
}

使用

ValueAnimator valueAnimator=ValueAnimator.ofObject(new PointXYEvaluator(),
            new PointXY(pointXY.getLeft(),pointXY.getTop()),new PointXY(pointXY.getLeft()+200,pointXY.getTop()+200));
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            PointXY pointValue= (PointXY) animation.getAnimatedValue();
            pointXY.setTranslationX(pointValue.getPointX());
            pointXY.setTranslationY(pointValue.getPointY());
        }
    });

    valueAnimator.start();
ValueAnimator ofObject 定義TypeEvaluator

參考:
自定義控件三部曲之動(dòng)畫篇(六)——ValueAnimator高級(jí)進(jìn)階(二)
Android動(dòng)畫學(xué)習(xí)(三)之使用ValueAnimator和ObjectAnimator實(shí)現(xiàn)動(dòng)畫實(shí)例

2脐瑰、 ObjectAnimator

ObjectAnimator動(dòng)畫原理

在ObjectAnimator中,則是先根據(jù)屬性值拼裝成對(duì)應(yīng)的set函數(shù)的名字廷臼,比如這里的scaleY的拼裝方法就是將屬性的第一個(gè)字母強(qiáng)制大寫后苍在,與set拼接,所以就是setScaleY荠商。然后通過反射找到對(duì)應(yīng)控件的setScaleY(float scaleY)函數(shù)寂恬,將當(dāng)前數(shù)字值做為setScaleY(float scale)的參數(shù)將其傳入。

常用的構(gòu)造函數(shù)有:

  • ObjectAnimator ofFloat(Object target, String propertyName, float... values)
    其中莱没,target指定這個(gè)動(dòng)畫要操作的是哪個(gè)控件
    propertyName指定這個(gè)動(dòng)畫要操作這個(gè)控件的哪個(gè)屬性
    values是可變長(zhǎng)參數(shù)初肉,就是指這個(gè)屬性值是從哪變到哪
  • ObjectAnimator ofFloat(Object target, String xPropertyName, String yPropertyName,Path path)
  • ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values)

代碼如下:

ObjectAnimator translationAnimator=ObjectAnimator.ofFloat(view,"translationY",0,-400).setDuration(400);
translationAnimator.start();

---

Path translationPath=new Path();
translationPath.moveTo(0,0);
translationPath.lineTo(200, 300);
ObjectAnimator translationAnimator=ObjectAnimator.ofFloat(v,"translationX","translationY",translationPath);
translationAnimator.start();

也可以在xml中進(jìn)行配置

    <objectAnimator android:duration="400"
        android:propertyName="translationY"
        android:valueFrom="0dp"
        android:valueTo="-200dp"
        android:valueType="floatType"/>

---

    Animator animator= AnimatorInflater.loadAnimator(Main2Activity.this,R.animator.object_animator);
    animator.setTarget(v);
    animator.start();

1、View屬性動(dòng)畫默認(rèn)的屬性值:translationX饰躲、translationY牙咏、x 臼隔、 y(view對(duì)象在它容器中的最終位置)、rotation妄壶、rotationX摔握、rotationY、scaleX丁寄、scaleY盒发、pivotX、pivotY(旋轉(zhuǎn)和縮放都是以此為中心展開的,缺省值是 View 對(duì)象的中心點(diǎn))狡逢、alpha...
2宁舰、如果在調(diào)用 ObjectAnimator 的某個(gè)工廠方法時(shí),我們只為 values... 參數(shù)指定了一個(gè)值奢浑,那此值將被認(rèn)定為動(dòng)畫屬性的結(jié)束值蛮艰。 這樣的話,動(dòng)畫顯示的屬性必須帶有一個(gè) getter 方法雀彼,用于獲取動(dòng)畫的起始值壤蚜。
3、還可以自定義屬性值徊哑,但要在操作的控件中袜刷,實(shí)現(xiàn)對(duì)應(yīng)的屬性的set方法

  • ObjectAnimator ofObject(T target, @NonNull Property<T, V> property, @Nullable TypeConverter<PointF, V> converter, Path path)
  • <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty, Property<T, Float> yProperty, Path path)
  • <T, V> ObjectAnimator ofObject(T target, @NonNull Property<T, V> property, @Nullable TypeConverter<PointF, V> converter, Path path)
    其中Property<T, V>是一個(gè)屬性包裝器,如下


    Property<View, Float> TRANSLATION_X

自定義Property莺丑,代碼如下:

public class ImgMoveView extends View {
    private static final String PROPERTY_NAME="position";
    public ImgMoveView(Context context) {
        super(context);
    }
    public ImgMoveView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public void setPosition(PointF position){
        int x = Math.round(position.x);
        int y = Math.round(position.y);
        setTranslationX(x);
        setTranslationY(y);
    }
    public PointF getPosition(){
        return new PointF(getX(),getY());
    }
    /**
     * A Property wrapper around the position functionality handled by the
     * ImgMoveView#setPosition(PointF) and ImgMoveView#getPosition() methods.
     */
    public static final Property<ImgMoveView, PointF> POSITION = new Property<ImgMoveView, PointF>(PointF.class,PROPERTY_NAME) {
        @Override
        public PointF get(ImgMoveView object) {
            return object.getPosition();
        }
        @Override
        public void set(ImgMoveView object, PointF value) {
            object.setPosition(value);
        }
    };
}

調(diào)用:

    /*ObjectAnimator pathMoveAnim=ObjectAnimator.ofFloat(imgMove, "translationX", "translationY", path);*/
    //ObjectAnimator pathMoveAnim=ObjectAnimator.ofFloat(imgMove, View.TRANSLATION_X, View.TRANSLATION_Y, path);
    ObjectAnimator pathMoveAnim=ObjectAnimator.ofObject(imgMove, ImgMoveView.POSITION,
            null, path);
使用Property

參考:自定義控件三部曲之動(dòng)畫篇(七)——ObjectAnimator基本使用著蟹、自定義控件三部曲之動(dòng)畫篇(八)——PropertyValuesHolder與Keyframe

3、監(jiān)聽器
屬性動(dòng)畫提供了AnimatorListener(監(jiān)聽Start梢莽、End萧豆、Cancel、Repeat事件)昏名、AnimatorUpdateListener (onAnimationUpdate())兩個(gè)監(jiān)聽器用于動(dòng)畫在播放過程中的重要?jiǎng)赢嬍录?/p>

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

4涮雷、AnimatorSet
如果一個(gè)動(dòng)畫用到了一個(gè)對(duì)象的多個(gè)屬性,可以使用AnimatorSet轻局;
可以通過playTogether()洪鸭、playSequentially()、play().with()仑扑、after()览爵、before()來控制執(zhí)行的順序

  • AnimatorSet
  • playTogether:同時(shí)開始執(zhí)行
  • playSequentially:依次按先后順序執(zhí)行,前一個(gè)動(dòng)畫執(zhí)行完夫壁,再執(zhí)行后一個(gè)動(dòng)畫
  • AnimatorSet.Builder
  • play():調(diào)用AnimatorSet中的play方法拾枣,獲取AnimatorSet.Builder對(duì)象沃疮,
  • with():和前面動(dòng)畫同時(shí)開始執(zhí)行
  • after(A):A先執(zhí)行盒让,然后執(zhí)行前面的動(dòng)畫
  • before(A):前面的動(dòng)畫先執(zhí)行梅肤,A后執(zhí)行

代碼如下:

AnimatorSet animatorSet=new AnimatorSet();
animatorSet.setDuration(1000);
Path translationPath=new Path();
translationPath.moveTo(0,0);
translationPath.lineTo(200, 300);
Path scalePath=new Path();
scalePath.moveTo(1,1);
scalePath.lineTo(0.5f,0.5f);
scalePath.lineTo(1f,1f);
ObjectAnimator translationAnimator=ObjectAnimator.ofFloat(v,"translationX","translationY",translationPath);
ObjectAnimator rotationAnimator=ObjectAnimator.ofFloat(v,"rotation",0,360);
ObjectAnimator scaleAnimator=ObjectAnimator.ofFloat(v,"scaleX","scaleY",scalePath);
//animatorSet.playTogether(translationAnimator,rotationAnimator);//同時(shí)
//animatorSet.playSequentially(translationAnimator,rotationAnimator);//相繼的
animatorSet.play(rotationAnimator).after(translationAnimator).before(scaleAnimator);
animatorSet.start();

---

AnimatorSet animatorSet=new AnimatorSet();
animatorSet.setDuration(1000);
ObjectAnimator translationAnimator=ObjectAnimator.ofFloat(v,"translationY",0,-400).setDuration(400);
ObjectAnimator translationAnimator2=ObjectAnimator.ofFloat(v,"translationY",-400,0).setDuration(400);
ObjectAnimator scaleAnimator=ObjectAnimator.ofFloat(v,"scaleX",1,0.1f,1).setDuration(200);
animatorSet.playSequentially(translationAnimator,scaleAnimator,translationAnimator2);//相繼的
animatorSet.start();
屬性動(dòng)畫2.gif
屬性動(dòng)畫3.gif

或者使用XML定義

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">

    <objectAnimator android:duration="400"
        android:propertyName="translationY"
        android:valueFrom="0dp"
        android:valueTo="-200dp"
        android:valueType="floatType"/>

    <objectAnimator android:duration="100"
        android:propertyName="scaleX"
        android:valueFrom="1.0"
        android:valueTo="0.1"
        android:valueType="floatType"/>

        ...

</set>

當(dāng)然,對(duì)于同一個(gè)對(duì)象的多個(gè)屬性邑茄,同時(shí)作用動(dòng)畫效果姨蝴,也可以使用PropertyValuesHolder,代碼如下:


    PropertyValuesHolder translationHolder=PropertyValuesHolder.ofFloat("translationY",-200);
    PropertyValuesHolder rotationHolder=PropertyValuesHolder.ofFloat("rotation",360);
    ObjectAnimator objectAnimator=ObjectAnimator.ofPropertyValuesHolder(v, translationHolder, rotationHolder);
    objectAnimator.setDuration(1000).start();
    objectAnimator.setInterpolator(new BounceInterpolator());

但是肺缕,它不能像AnimatorSet 一樣左医,控制動(dòng)畫執(zhí)行的順序

PropertyValueHolder

5、插值器
插值器定義了動(dòng)畫變化過程中的變化規(guī)則同木,需要實(shí)現(xiàn)Interpolator接口

publicinterfaceTimeInterpolator{
floatgetInterpolation(floatinput);
}

其中

  • input參數(shù):只與時(shí)間有關(guān)浮梢,取值范圍是0到1,表示當(dāng)前動(dòng)畫的進(jìn)度彤路,取0時(shí)表示動(dòng)畫剛開始秕硝,取1時(shí)表示動(dòng)畫結(jié)束
  • 返回值:動(dòng)畫的當(dāng)前 數(shù)值進(jìn)度。取值可以超過1也可以小于0洲尊,超過1表示已經(jīng)超過目標(biāo)值远豺,小于0表示小于開始位置。但這個(gè)數(shù)值是百分比的坞嘀,不是具體數(shù)值躯护,在監(jiān)聽器返回之前,還需要Evaluator進(jìn)行轉(zhuǎn)換

Android系統(tǒng)本身內(nèi)置了一些通用的Interpolator(插值器),如下:
@android:anim/accelerate_interpolator: 越來越快
@android:anim/decelerate_interpolator:越來越慢
@android:anim/accelerate_decelerate_interpolator:先快后慢
@android:anim/anticipate_interpolator: 先后退一小步然后向前加速
@android:anim/overshoot_interpolator:快速到達(dá)終點(diǎn)超出一小步然后回到終點(diǎn)
@android:anim/anticipate_overshoot_interpolator:到達(dá)終點(diǎn)超出一小步然后回到終點(diǎn)
@android:anim/bounce_interpolator:到達(dá)終點(diǎn)產(chǎn)生彈球效果丽涩,彈幾下回到終點(diǎn)
@android:anim/linear_interpolator:均勻速度棺滞。

左右循環(huán)擺動(dòng)cycleInterpolator
<!--@anim/cycle_2  -->
<!--定義cycleInterpolator  -->
<?xml version="1.0" encoding="utf-8"?>
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:cycles="2"/>

<!--@anim/shake_error  -->
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0%"
    android:toXDelta="2%"
    android:duration="300"
    android:interpolator="@anim/cycle_2"/>

//加載動(dòng)畫
Login.startAnimation(AnimationUtils.loadAnimation(LoginActivity.this,R.anim.shake_error));

默認(rèn)的插值器

參考:
android動(dòng)畫 Interpolator自定義控件三部曲之動(dòng)畫篇——插值器

6矢渊、Evaluator
根據(jù)插值器返回的數(shù)字進(jìn)度轉(zhuǎn)成具體數(shù)值检眯;在AnimatorUpdateListener的animation.getAnimatedValue()函數(shù)拿到的就是Evaluator中返回的數(shù)值;系統(tǒng)本身內(nèi)置了一些Evalutor昆淡,如IntEvaluator锰瘸、FloatEvaluator、ArgbEvalutor

自定義Evaluator昂灵,需要實(shí)現(xiàn)TypeEvaluator<T>避凝,要注意動(dòng)畫數(shù)值類型

publicinterfaceTypeEvaluator<T>{
T  evaluate(floatfraction,T startValue,T endValue)
}
  • fraction:加速器中的返回值,表示當(dāng)前動(dòng)畫的數(shù)值進(jìn)度
  • startValue和endValue分別對(duì)應(yīng)ofInt(int start,int end)中的start和end的數(shù)值眨补;

參考:自定義控件三部曲之動(dòng)畫篇——Evaluator管削、Android 動(dòng)畫學(xué)習(xí)(二)之Property Animation初步介紹

7、Keyframe關(guān)鍵幀
KeyframeSet是關(guān)鍵幀的集合撑螺,Keyframe是一個(gè)動(dòng)畫保存time/value(時(shí)間與值)對(duì)

關(guān)鍵幀

ofInt就是記錄了target,propName,values(是將我們傳入的int型values含思,輾轉(zhuǎn)轉(zhuǎn)化成了PropertyValuesHolder),以及一個(gè)mValueMap,這個(gè)map的key是propName,value是PropertyValuesHolder含潘,在PropertyValuesHolder內(nèi)部又存儲(chǔ)了proprName, valueType , keyframeSet等等

自定義控件三部曲之動(dòng)畫篇(八)——PropertyValuesHolder與Keyframe饲做、Android 屬性動(dòng)畫 源碼解析 深入了解其內(nèi)部實(shí)現(xiàn)Android Property Animation(屬性動(dòng)畫)原理分析

8遏弱、View的animate()方法

可以使用View的animate()方法直接驅(qū)動(dòng)屬性動(dòng)畫

    view.animate().y(100).scaleX(0.1f).setDuration(1000).withStartAction(new Runnable() {
        @Override
        public void run() {
        }
    }).withEndAction(new Runnable() {
        @Override
        public void run() {
        }
    }).start();

</br>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盆均,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子漱逸,更是在濱河造成了極大的恐慌泪姨,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饰抒,死亡現(xiàn)場(chǎng)離奇詭異肮砾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)袋坑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門唇敞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咒彤,你說我怎么就攤上這事疆柔。” “怎么了镶柱?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵旷档,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我歇拆,道長(zhǎng)鞋屈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任故觅,我火速辦了婚禮厂庇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘输吏。我一直安慰自己权旷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布贯溅。 她就那樣靜靜地躺著拄氯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪它浅。 梳的紋絲不亂的頭發(fā)上译柏,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音姐霍,去河邊找鬼鄙麦。 笑死典唇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的胯府。 我是一名探鬼主播介衔,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼盟劫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起与纽,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤侣签,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后急迂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體影所,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年僚碎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猴娩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勺阐,死狀恐怖卷中,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渊抽,我是刑警寧澤蟆豫,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站懒闷,受9級(jí)特大地震影響十减,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜愤估,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一帮辟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玩焰,春花似錦由驹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蒿赢,卻和暖如春润樱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背羡棵。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工壹若, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓店展,卻偏偏與公主長(zhǎng)得像养篓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赂蕴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容