Animator

2016/08/09

分类

Android动画分为两类:ViewAnimation(TweenAimation, FrameAnimation)和PropertyAnimator(ValueAnimator, ObjectAnimator)

引入PropertyAnimator的作用

  1. 能实现TweenAnimation无法实现的动画
  2. 改变View的某一属性做动画,ViewAnimation仅对View做动画
  3. ViewAnimation点击区域还在动画播放之前

1. TweenAimation

  • xml设置
  • AlphaAnimation
  • ScaleAnimation
  • TranslateAnimation
  • RotateAnimation

用法

  1. xml共同属性:
    • fillAfter:如果true,动画结束,将保持动画最后时的状态
    • fillBefore、fillEnable:如果true,动画结束,将还原到开始动画前的状态
    • repeatCount:重复次数;repeaterMode:重复类型,有reverse倒序重放和restart重新播放。一起使用
    • interpolator:设置插值器,即指定动作效果。
    android:fillBefore="true"  
    android:repeatCount="1"  
    android:repeatMode="restart" 
    
  2. Interpolator 插值器
    • AccelerateDecelerateInterpolator:动画开始结束比较慢,中间加速
    • AccelerateInterpolator:动画开始比较慢,然后加速
    • AnticipateInterpolator:开始向前,然后向后甩
    • BounceInterpolator:开始向后,然后向前甩一定值后,返回最后的值
    • CycleInterploator:循环播放特定的次数,速度改变沿着正弦曲线
    • DecelerateInterpolator:开始快,然后慢
    • LinearInterpolator:线性速度改变
    • OvershootInterpolator:向前甩一定值,再回到原来位置
  3. 公共类Animation
    • setFillAfter/Before/Enable(boolean)
    • setRepeatCount(int), setRepeatMode(int)
    • setInterpolator(Interpolator)

2. FrameAnimation

帧动画又称为Drawable Animation,就是通过一系列的Drawable依次显示来达到模拟动画的效果。

使用

  1. xml

    ``` res/drawable/ drawable_animation.xml

	```
ImageView image = (ImageView) findViewById(R.id.image);
image.setBackgroundResource(R.drawable.drawable_animation);
AnimationDrawable animation = (AnimationDrawable) image.getBackground();
animation.start();
  1. 代码

    ImageView image = findViewById(R.id.image);
    image.setBackgroundResource(R.drawable.drawable_animation);
    AnimationDrawable animation = image.getBackground();
    animation.addFrame(getResources().getDrawable(R.drawable.frame1), 200);
    animation.addFrame(getResources().getDrawable(R.drawable.frame2), 200);
    animation.addFrame(getResources().getDrawable(R.drawable.frame3), 200);        
    animation.start();
    

方法

  • start/stop()
  • addFrame(Drawable frame, int duration), 设置一帧,和持续时间
  • setOneShoe(boolean flag), true 播放一次,false 循环播放
  • isRunning(), 是否正在播放

3. ValueAnimator

  1. ValueAnimator不会对View做任何操作,而是去设定值
  2. 用法:创建ValueAnimator,添加监听

    ValueAnimator animator = ValueAnimator.ofInt(0,400);  
    animator.setDuration(1000);  
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
     @Override  
     public void onAnimationUpdate(ValueAnimator animation){  
         int curValue = (int)animation.getAnimatedValue();  
     }  
    });  
    animator.start(); 
    
  3. 监听器(ObjectAnimator也适用)

    监听器一:监听动画变化时的实时值  
    public static interface AnimatorUpdateListener {  
     void onAnimationUpdate(ValueAnimator animation);  
    }  
    //添加方法为:public void addUpdateListener(AnimatorUpdateListener listener)  
    监听器二:监听动画变化时四个状态 
    public static interface AnimatorListener {  
     void onAnimationStart(Animator animation);  
     void onAnimationEnd(Animator animation);  
     void onAnimationCancel(Animator animation);  
     void onAnimationRepeat(Animator animation);  
    }  
    //添加方法为:public void addListener(AnimatorListener listener)
    取消监听(并未cancel动画)
    void removeUpdateListener(AnimatorUpdateListener listener);  
    void removeAllUpdateListeners(); 
    void removeListener(AnimatorListener listener);  
    void removeAllListeners();
    
  4. 其他方法
    • setStartDelay(long)
    • clone:所有的动画效果都一样,但cancel需要自己调用(原来的Animator.cancel后会clone的不起作用)。
    • ValueAnimator ofObject()(TypeEvalutor evaluator, Object … values);自定义的Evaluator,可变长度Object
  5. PropertyValuesHolder 保存了动画过程中所需要操作的属性和对应的值 ObjectAnimator ofPropertyValuesHoiler(Object target, PropertyValuesHodler…values) PropertyValuesHolder ofKeyframe(String propertyName, Keyframe… values)

4. ObjectAnimator

摘抄自http://wiki.jikexueyuan.com/project/android-animation/7.html

作用

  1. 动画直接与View相关联,从动画监听过程中解放出来

方法

  1. extends ValueAnimator, override ofInt(), ofFloat()
  2. ObjectAnimator ofFloat(Object target, String propertyName, float… values)
    • target: 动画绑定的View
    • propertyName:指定动画操作的属性
    • values:可变长参数,属性值by,to
    ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"alpha",1,0,1);  
    animator.setDuration(2000);  
    animator.start(); 
    
  3. ObjectAnimator做动画时会去target View中找对应的set方法来改变对应的属性。View中有关动画,包含以下几组set方法

    //透明度
    public void setAlpha(float alpha)  
    //旋转
    public void setRotation(float rotation)  
    public void setRotationX(float rotationX)  
    public void setRotationY(float rotationY)  
    //位置
    public void setTranslationX(float translationX)   
    public void setTranslationY(float translationY)  
    //缩放
    public void setScaleX(float scaleX)  
    public void setScaleY(float scaleY)
    
  4. 自定义动画注意:
    • 设置set方法,动画使用的propertyName与此名称相同
    • 动画(如ofInt)只有一个过渡值时,会调用get方法。
    • 动画将View的属性从value1 -> value2 -> value3
  5. Evaluator
    • 动画变化过程:定义动画数字区间通过监听器返回当前动画对应数值过程。
     ofInt(0,400) --> 加速器 -----> Evaluator ---->  监听器返回
     定义动画值	 返回当前数字进度  根据进度计算当前值   AnimatorUpdateListener中返回
    

    Evaluator计算当前值就是一个转换器。

    • 各种Evaluator
     ValueAnimator animator = ValueAnimator.ofInt(0, 600);
     animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()) {
         @Override
         public void onAnimatorUpdate(ValueAnimator animation) {
             int curValue = (int) animation.getAnimatedValue();
         }
     }
    

    对Evaluator而言,ofInt对应的是IntEvaluator。(int)(startIntent + fraction * (endValue - startInt))。即当前动画对应的数值。不能通用,也不可强转。

    • 使用ArgbEvaluator;设置颜色,在TextView中setBackground去修改颜色
    ObjectAnimator animator = ObjectAnimator.ofInt(tv, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);  
    animator.setDuration(8000);  
    animator.setEvaluator(new ArgbEvaluator());  
    animator.start();
    
    • 插值器
    //设置插值器 
    public void setInterpolator(TimeInterpolator value)  
    //设置 Evaluator 
    public void setEvaluator(TypeEvaluator value) 
    
    • 自定义Evaluator: 实现TypeEvaluator,保证定义动画使用的数值类型与Evaluator的返回值类型一样。
    public class IntEvaluator implements TypeEvaluator<Integer> {
      //如果ofInt(0, 400),则此时返回值应该是(200, 600). reverse (400, 0);
     @Override
     public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
         int startInt = startValue;
         return (int) (200 + startInt + fraction * (endValue - startInt));
    //        return (int) (endValue - fraction * (endValue - startValue));
     }
    }
    
  6. 其他动画

    // 设置动画时长,单位是毫秒  
    ValueAnimator setDuration(long duration)  
    //获取 ValueAnimator 在运动时,当前运动点的值 
    Object getAnimatedValue();  
    //设置循环次数,设置为 INFINITE 表示无限循环   
    void setRepeatCount(int value)  
    //设置循环模式 
    value 取值有 RESTART,REVERSE,  
    void setRepeatMode(int value)  
    

原理

5. Transition

1. Activity Fragment过渡动画

  1. xml设置

    ```


2. 代码设置

	```
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);//onCreate
setExitTransition() - 当A start B时,A中View退出 
setEnterTransition() - 当A start B时,B中View进入 
setReturnTransition() - 当B 返回 A时,B中View退出 
setReenterTransition() - 当B 返回 A时,A中View进入
  1. 共享元素 ` android:transitionName=”shareName” ,在B中 startActivity(intent, ActivityOptions. makeSceneTransitionAnimation(this, view, “share”).toBundle());`

多个共享元素,可通过Pair.create()来创建,startActivity(intent, ActivityOptions.makeSceneTransitionAnimation (this, Pair.create(view, "share"), Pair.create(fab,"fab")).toBundle());

2. ViewGroup过渡动画

res/layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/master_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/title"
        ...
        android:text="Title"/>
    <FrameLayout
        android:id="@+id/scene_root">
        <include layout="@layout/scene_first" />
    </FrameLayout>
</LinearLayout>

res/layout/scene_first.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:id="@+id/text_view1
        android:layout_width="match_parent"
	     android:layout_height="wrap_content"
        android:text="Text Line 1" />
    <TextView
        android:id="@+id/text_view2
        android:text="Text Line 2" />
</RelativeLayout>

代码设置

Scene mFirstScene;
Scene mSecondScene;
 
// Create the scene root for the scenes in this app
mSceneRoot = (ViewGroup) findViewById(R.id.scene_root);
 
// Create the scenes
mFirstScene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene_first, this);
mSecondScene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene_second, this);
mFirstScene = new Scene(mSceneRoot, mSceneRoot.findViewById(R.id.scene_first))

TransitionManager.go(mSecondScene, new Fade());

3. 使用

  1. explode,从屏幕中间,slide,fade
  2. xml 与 代码
res/transition/fade_transition.xml
<fade xmlns:android="http://schemas.android.com/apk/res/android" />
 
在代码中调用 Transition mFadeTransition =
        TransitionInflater.from(this).
        inflateTransition(R.transition.fade_transition);
也可以完全通过代码创建:
Transition mFadeTransition = new Fade();
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeBounds />
    <fade android:fadingMode="fade_in" />
        <targets>
        	 <!-- 应用到某个对象上  -->
            <target android:targetId="@id/transition_title" />
        </targets>
    </fade>
</transitionSet>   
changeBound 这个是最长使用的 改变View 大小和位置
changeClipBounds 改变 Clip 边界的大小
changeImageTransform 改变ImageView 的大小 和 martix
ChangeTransform 改变普通的 View 一些Scalex 值
ChangeScroll 改变滑动位置
</transitionSet>

或者在代码中
TransitionSet set = new TransitionSet();
set.addTransition(new Fade())
    .addTransition(new ChangeBounds())
    .addTransition(new AutoTransition());
res/transition/transition_manager.xml

<transitionManager xmlns:app="http://schemas.android.com/apk/res-auto">
    <transition
        app:fromScene="@layout/scene1"
        app:toScene="@layout/scene2"
        app:transition="@transition/trans_scene1_to_scene2" />
    <transition
        app:fromScene="@layout/scene2"
        app:toScene="@layout/scene1"
        app:transition="@transition/trans_scene2_to_scene1" />
    ...
</transitionManager>

5. 原理

使用Transitions API为安卓应用创建动画 英文原文

采用Scene(场景),即对VIewGroup的一层封装,描述所有View的状态。Transition机制:读取不同场景之间View属性的变化,从而产生让这种变化看起来更加平滑的动画。

public static interface TransitionListener {
   void onTransitionStart(Transition transition);
 
   void onTransitionEnd(Transition transition);
 
   void onTransitionCancel(Transition transition);
 
   void onTransitionPause(Transition transition);
 
   void onTransitionResume(Transition transition);
}

6. ViewFilpper

  1. method
    • start/stopFlipping()
    • isAutoStart(), setAutoStart()
    • setFlipInterval(int milliseconds)
    • onAttached/DetachedFromWindow(), getWindowVisibilityChanged

7. ViewPropertyAnimator

` view.animate().x(50).setAlpha(0.5f)`

  • animate():从调用 View 对象的 animate() 方法开始,该方法返回一个 ViewPropertyAnimator 实例,然后就可以调用它的方法来设置动画参数。
  • 自动开始:要注意上述代码并未调用 start() 方法,因为在新 API 中动画启动是隐式的,一旦设置完成后,这些动画就「立刻」「一起」启动了。如果要深究细节的话,其实也并非「立刻」启动,而是在下一次 UI 刷新时。ViewPropertyAnimator 正是利用了这个时间差,把所有声明的动画收集在一起。只要还在继续声明新的动画,那么所有动画就会继续等待下一次 UI 刷新。一旦完成声明,所有动画就在下一次 UI 刷新时一起启动了。当然我们也可以显示调用start()来启动动画。
  • 流式接口:ViewPropertyAnimator 拥有流式接口(Fluent interface),允许函数链式调用,使得在一行代码中可以构建多个属性动画。

关于性能

  1. 能够直接修改目标视图的属性。

  2. 只需构建一个 Animator 就可以实现多个动画。如果采用 AnimatorSet 实现的话,需要这样做,这段代码创建了两个 Animator 对象(也就是两个独立的动画),然后通过 AnimatorSet 同时播放:

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

或者使用 PropertyValuesHolder,只构造一个 Animator 对象来同时实现多个属性动画:

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start(); 而使用 ViewPropertyAnimator 实现的代码已经在上节内容中提到了。
  1. ViewPropertyAnimator 会在每一个动画帧,计算变化的属性值并设置给属性,然后只调用一次 invalidate 进行重绘。代替每一个属性单独计算、单独重绘。

摘自ViewPropertyAnimator的介绍

功能

1. TweenAnimation

1.AlphaAnimation

  1. xml属性:form/toAlpha:0.0-1.0透明度
  2. 代码设置: AlphaAnimation(float fromAlpha, float toAlpha)

2. ScaleAnimation

  1. xml属性:
    • from/toX/YScale:起始/结束X/Y方向相对自身缩放比例。
    • pivotX/Y:缩放起点X/Y坐标,可以是50,50%,50%p;缩放点:数值–View的左上角+Value(px);%–View左上角+view.getWidth()/2;%p–View左上角+parentView.getWidth()/2.

    ``` <?xml version=”1.0” encoding=”utf-8”?>

``` 2. 代码设置: 
* 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)
* pivotXType 和 pivotYType 的选择,同样有三个取值:Animation.ABSOLUTE、Animation.RELATIVE_TO_SELF 和 Animation.RELATIVE_TO_PARENT;

3. TranslateAnimation

  1. xml属性:
    • form/toX/YDelta:起始/结束X/Y坐标,有三种值50,50%,50%p,yu Scale同

    ```

</translate>

2. 代码设置:
	* 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. RotateAnimation
1. xml属性:
	* form/toDegrees:开始/结束旋转的角度位置,+顺时针,-逆时针度数
	* pivotX/Y:与Scale同
	
	```
	<?xml version="1.0" encoding="utf-8"?>  
<rotate xmlns:android="http://schemas.android.com/apk/res/android"  
    android:fromDegrees="0"  
    android:toDegrees="-650"  
    android:pivotX="50%"  
    android:pivotY="50%"  
    android:duration="3000"  
    android:fillAfter="true">  
</rotate> 
  1. 代码设置:
    • 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)

2. 自定义动画

1. (Tween)set动作合集

set标签extends Animation的属性。 * xml

<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:duration="3000"  
    android:fillAfter="true">  
  <alpha   
    android:fromAlpha="0.0"  
    android:toAlpha="1.0"/>  
  <scale  
    android:fromXScale="0.0"  
    android:toXScale="1.4"  
    android:fromYScale="0.0"  
    android:toYScale="1.4"  
    android:pivotX="50%"  
    android:pivotY="50%"/>  
  <rotate  
    android:fromDegrees="0"  
    android:toDegrees="720"  
    android:pivotX="50%"  
    android:pivotY="50%"/>  
</set>  
* AnimationSet(boolean shareInterpolator) shareInterpolator 取值 true 或 false,取 true 时,指在 AnimationSet 中定义一个插值器(interpolater),它下面的所有动画共同。如果设为 false,则表示它下面的动画自己定义各自的插值器。
alphaAnim = new AlphaAnimation(1.0f,0.1f);  
scaleAnim = new ScaleAnimation(0.0f,1.4f,0.0f,1.4f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);  
rotateAnim = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);  

setAnim=new AnimationSet(true);  
setAnim.addAnimation(alphaAnim);  
setAnim.addAnimation(scaleAnim);  
setAnim.addAnimation(rotateAnim);  

setAnim.setDuration(3000);  
setAnim.setFillAfter(true);

2. 3d旋转

转自http://www.bkjia.com/Androidjc/997572.html 类似以下动画,需自定义完成。

步骤
  1. extends Animation, override applyTransformation(float interpolatedTime, Transformation t), initialize两个方法。
  2. applyTranslation params:
    • interpolatedTime: 时间的进行程度(0-1s,1s动画结束)
    • transformation: 动画在不同时刻对图形和组件的变形程度。该对象封装了一个Matrix对象,translation会控制组件随着Matrix的变换而进行相应变换。
  3. initialize(int width, int height, int parentWidth, int parentHeight),该回调函数通知Animation目标View的大小参数。可初始化一些相关参数,如动画持续时间,interpolator,动画参考点等。
  4. 为了控制view进行三维变换,需要借助于Android提供的Camera类,其作用类似于Matrix,提供如下方法:
    • getMatrix(Matrix matrix);将Camera所做的变换应用到制定的matrix上
    • rotateX/Y/Z(float degrees);将view沿X/Y/Z轴旋转
    • translate(float x, float y, float z);在三维空间进行位置变换
    • applyToCanvas(Canvas canvas);将Camera所做的变换应用到Canvas上
    • getLocationX/Y/Z();
    • save(), restore();
    • dotWithNormal();

2. 自定义Interpolator

  1. 以此为例LinearInterpolator extends Interpolator implements TimeInterpolator
    • float getInterpolation(float input): 0-1动画在时间上的进度,return值是动画的Value进度
  2. 自定义:override getInterpolation()

3 源码敬上

4 自定义View的动画 postOnAnimation

public class PathView extends RelativeLayout {

    private Paint mPaint = new Paint();
    private Path drawingPath = new Path();
    private int mPaintColor = Color.WHITE;
    private int mLastRaidus = 0;
    private int mCurRaidus = 20;
    private PathItemView mItemView;

    public PathView(Context context) {
        super(context);
        init();
    }

    private void init() {
        setWillNotDraw(false);
        mItemView = new PathItemView(getContext());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLACK);
        mPaint.setStrokeWidth(4f);
        mPaint.setColor(mPaintColor);
        mPaint.setStyle(Paint.Style.STROKE);
        drawingPath.moveTo(10, 10);
        drawingPath.lineTo(200, 140);
        canvas.drawPath(drawingPath, mPaint);
        setCircle(canvas);
    }

    private void setCircle(Canvas canvas) {
        if (mCurRaidus >= mLastRaidus && mCurRaidus < 20) {
            mCurRaidus++;
        } else if (mCurRaidus <= mLastRaidus && mCurRaidus > 11) {
            mCurRaidus--;
        } else {
            mLastRaidus = mCurRaidus;
        }
        mPaint.setStrokeWidth(3f);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.WHITE);
        mPaint.setAlpha(255);
        canvas.drawCircle(200, 200, mCurRaidus, mPaint);
        postOnAnimation(new Runnable() {
        	@override
        	public void run() {
        	  postInvalidate();
        }});
    }

}

文内导航