深入浅析安卓动画体系

来源:互联网 发布:新开淘宝店铺怎么宣传 编辑:程序博客网 时间:2024/05/17 22:15

Android进阶–动画

Android进阶路线图

一、Android基础动画

1、平移动画Translation

  • a、 xml方式实现(在res目录下建立anim目录)

    animator_translate.xml

    <?xml version="1.0" encoding="utf-8"?><translate    xmlns:android="http://schemas.android.com/apk/res/android"    android:fromXDelta="0"    android:fromYDelta="0"    android:toYDelta="0"    android:toXDelta="200"    android:duration="500"    android:fillAfter="true"></translate>

    代码加载xml文件获取动画

    //加载动画Animation animation = AnimationUtils.loadAnimation(this, R.anim.animator_translate);//执行动画testBtn.startAnimation(animation);

  • b、 代码方式实现

    TranslateAnimation translateAnimation = new TranslateAnimation(0,200,0,0);translateAnimation.setDuration(500);//动画执行时间translateAnimation.setFillAfter(true);//动画执行完成后保持状态//执行动画testBtn.startAnimation(translateAnimation);

2、旋转动画Rotation

  • a、 xml方式实现

    animator_rotation.xml

    <?xml version="1.0" encoding="utf-8"?><rotate    xmlns:android="http://schemas.android.com/apk/res/android"    android:fromDegrees="0"    android:toDegrees="90"    android:pivotX="50%"    android:pivotY="50%"    android:duration="500"    android:fillAfter="true"></rotate>

    代码加载xml文件获取动画

    Animation animation = AnimationUtils.loadAnimation(this, R.anim.animator_rotation);testBtn.startAnimation(animation);
  • b、 代码方式实现

    RotateAnimation rotateAnimation = new RotateAnimation(0,90,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);rotateAnimation.setDuration(500);rotateAnimation.setFillAfter(true);testBtn.startAnimation(rotateAnimation);

3、缩放动画Scale

  • a、 xml方式实现

    animator_scal.xml

    <?xml version="1.0" encoding="utf-8"?><scale    xmlns:android="http://schemas.android.com/apk/res/android"    android:fromXScale="1"    android:fromYScale="1"    android:toYScale="2"    android:toXScale="2"    android:duration="500"    android:pivotX="50%"    android:pivotY="50%"    android:fillAfter="true"></scale>

    代码加载xml文件获取动画

    Animation animation = AnimationUtils.loadAnimation(this, R.anim.animator_scal);testBtn.startAnimation(animation);
  • b、 代码方式实现

    ScaleAnimation scaleAnimation = new ScaleAnimation(1,2,1,2,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);scaleAnimation.setDuration(500);scaleAnimation.setFillAfter(true);testBtn.startAnimation(scaleAnimation);

4、透明度动画Alpha

  • a、 xml方式实现

    animator_alpha.xml

    <?xml version="1.0" encoding="utf-8"?><alpha    xmlns:android="http://schemas.android.com/apk/res/android"    android:fromAlpha="1"    android:toAlpha="0.2"    android:duration="500"    android:fillAfter="true"></alpha>

    代码加载xml文件获取动画

    Animation animation = AnimationUtils.loadAnimation(this, R.anim.animator_alpha);testBtn.startAnimation(animation);
  • b、 代码方式实现

    AlphaAnimation alphaAnimation = new AlphaAnimation(1,0.2f);alphaAnimation.setDuration(500);alphaAnimation.setFillAfter(true);testBtn.startAnimation(alphaAnimation);

5、帧动画

  • a、 xml方式实现(在drawable文件夹下定义xml)
    anim_list.xml
    这里写图片描述

    布局

    <ImageView    android:id="@+id/iv"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:background="@drawable/anim_list"/>

    获取背景

    //获取背景,并将其强转成AnimationDrawableAnimationDrawable animationDrawable = (AnimationDrawable) iv.getBackground();//判断是否在运行if(!animationDrawable.isRunning()){    //开启帧动画    animationDrawable.start();}
  • b、 代码方式实现

    //创建一个AnimationDrawableAnimationDrawable animationDrawable1 = new AnimationDrawable();int[] ids = {R.drawable.anim_1,R.drawable.anim_2,R.drawable.anim_3,R.drawable.anim_4};//通过for循环添加每一帧动画for(int i = 0 ; i < 4 ; i ++){    Drawable frame = getResources().getDrawable(ids[i]);    animationDrawable1.addFrame(frame,200);}animationDrawable1.setOneShot(false);//设置背景iv.setBackground(animationDrawable1);//开启帧动画animationDrawable1.start();

二、属性动画

1、ObjectAnimator

a、平移动画

//testBtn.animate().translationX(200);ObjectAnimator animator = ObjectAnimator.ofFloat(testBtn, "translationX", 200);//setTranslationXanimator.setDuration(500);animator.start();

b、旋转动画

ObjectAnimator animator = ObjectAnimator.ofFloat(testBtn,"rotation",90);animator.setDuration(500);animator.start();

c、缩放动画

ObjectAnimator animator = ObjectAnimator.ofFloat(testBtn,"scaleX",1.5f);animator.setDuration(500);animator.start();

d、透明度动画

ObjectAnimator animator = ObjectAnimator.ofFloat(testBtn,"alpha",0.2f);animator.setDuration(500);animator.start();

5、PropertyValuesHolder

上面的示例中一个ObjectAnimator只能改变一个属性,如果想通过一个ObjectAnimator改变多个属性,则需要使用PropertyValuesHolder

//一个ObjectAnimator通过PropertyValuesHolder可以同时改变多个属性PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationX",200);PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("translationY",200) ;ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(testBtn, holder1, holder2);animator.setDuration(500);animator.start();

e、关键帧Keyframe

//关键帧//首先定义关键帧Keyframe keyframe1 = Keyframe.ofFloat(0,0);Keyframe keyframe2 = Keyframe.ofFloat(0.5f,200);Keyframe keyframe3 = Keyframe.ofFloat(1,150);//将关键帧作用于属性上PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3);PropertyValuesHolder holder1 = PropertyValuesHolder.ofKeyframe("translationY",keyframe1,keyframe2,keyframe3);ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(testBtn,holder,holder1);animator.setDuration(500);animator.start();

f、补间器(差值器)

  • 系统自带补间器(差值器)
Interpolator 资源ID 功能 AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 先加速再减速 AccelerateInterpolator @android:anim/accelerate_interpolator 加速 AnticipateInterpolator @android:anim/anticipate_interpolator 先后退一小步然后加速前进 AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 先后退一小步再加速前进,超出终点一小步再回到终点 BounceInterpolator @android:anim/bounce_interpolator 最后阶段弹球效果 CycleInterpolator @android:anim/cycle_interpolator 周期运行 DecelerateInterpolator @android:anim/decelerate_interpolator 减速 LinearInterpolator @android:anim/linear_interpolator 匀速 OvershootInterpolator @android:anim/overshoot_interpolator 快速到达终点并超出一小步然后回到终点

//补间器 差值器
ObjectAnimator animator = ObjectAnimator.ofFloat(testBtn, “translationX”, 100,400);//setTranslationX
animator.setDuration(500);
//animator.setInterpolator(new AccelerateDecelerateInterpolator());//先加速后减速
animator.setInterpolator(new AnticipateOvershootInterpolator());//先后退一小步再加速前进,超出终点一小步再回到终点
animator.start();

  • 自定义补间器(差值器)

    //默认是LinearInterpolatoranimator.setInterpolator(new TimeInterpolator() {    @Override    public float getInterpolation(float input) {        //input 百分比(范围 0 - 1 ) 0.1 0.3 0. 5 只与时间有关        //上面我们定义动画执行时间是500  如果过了200  input=0.4        // 与自己设定的值无关 只与时间有关        Log.i("ObjeceAnimator","interpolation result :"+(1 - input));        return 1 - input;// 1 ---- 0 我们可以根据input自定义返回值    }});

g、Evaluator计算规则

Evaluator是计算规则,系统提供了一些默认的计算规则(FloatEvaluator IntEvaluator)

  • 自定义计算规则Evaluator

    //如果上面使用的是ofFloat 默认使用FloatEvaluator 如果是ofInt 默认使用IntEvaluatoranimator.setEvaluator(new TypeEvaluator<Float>() {    @Override    public Float evaluate(float fraction, Float startValue, Float endValue) {        //在这个方法里,我们可以任意的自定义计算规则        float result = startValue + (endValue - startValue) * fraction ;        Log.i("ObjeceAnimator","evaluator fraction:"+fraction+",result:"+result);        return result ;    }});

h、监听

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {        @Override        public void onAnimationUpdate(ValueAnimator valueAnimator) {            float fraction = valueAnimator.getAnimatedFraction();            float value = (float) valueAnimator.getAnimatedValue();            Log.i("ObjeceAnimator","update fraction:"+fraction+",value:"+value);        }    });
  • Interpolation 中的getInterpolation方法的返回值 负责计算百分比 只和时间有关
  • Evaluator 中的evaluate方法根据百分比和开始结束值计算value
  • UpdateListener中的fraction和value都是上面计算的结果

2、ValueAnimator

a、ValueAnimator理解

  • 1、ValueAnimator只提供变化量,并不真正的作用于view上
  • 2、ValueAnimator根据补间器Interpolator(差值器)时间产生百分比
  • 3、ValueAnimator根据Evaluator的计算规则和第2步中的百分比,计算value值
  • 4、ValueAnimator中的UpdateListener监听获取百分比和value
  • ValueAnimator是动画基础,可以在此基础上完成想要的任何动画

    ValueAnimator animator = ValueAnimator.ofFloat(100,200);animator.setDuration(500);animator.start();animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    @Override    public void onAnimationUpdate(ValueAnimator animation) {        float fraction = animation.getAnimatedFraction();        float value = (float) animation.getAnimatedValue();        //在这里设置动画属性        testBtn.setTranslationX(value);        Log.i("ObjectAnimator","fraction:"+fraction+",value:"+value);    }});

b、ValueAnimator.ofObject使用

  • Evaluator作用:提供计算规则
  • 强调:无论什么类型都需要计算规则Evaluator
  • ofFloat:系统默认提供FloatEvaluator
  • ofInt:系统默认提供IntEvaluator
  • ofObject:系统不知道使用的具体类型,同时又需要计算规则,这时就需要我们自己提供计算规则

    ValueAnimator animator = ValueAnimator.ofObject(new CharEvaluator(),new Character('a'),new Character('z'));animator.setDuration(10000);animator.start();animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    @Override    public void onAnimationUpdate(ValueAnimator animation) {        char value = (char) animation.getAnimatedValue();        testBtn.setText("测试"+value);    }});
  • ofObject针对自定义类型

    自定义类型

    public class Point {    private int pointX = 0 ;    public Point(int pointX) {        this.pointX = pointX;    }    public int getPointX() {        return pointX;    }    public void setPointX(int pointX) {        this.pointX = pointX;    }}

    自定义view代码如下

    public class PointView extends View {    private Paint paint ;           public PointView(Context context) {        super(context);        init();    }           public PointView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        init();    }           public PointView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }           public PointView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        init();    }           private void init(){        paint = new Paint() ;        paint.setColor(Color.RED);        paint.setStyle(Paint.Style.FILL);        paint.setAntiAlias(true);    }           private int cx = 0 ;    private int cy = 100 ;          @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //绘制圆               canvas.drawCircle(cx+20,cy,20,paint);           }    //开启动画方法    public void startAnimator(){        ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(),new Point(0),new Point(300));        animator.setDuration(1000);        animator.start();        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                Point point = (Point) animation.getAnimatedValue();                cx = point.getPointX();                //重绘                invalidate();            }        });    }    //自定义Point类型的计算规则    class PointEvaluator implements TypeEvaluator<Point>{        @Override        public Point evaluate(float fraction, Point startValue, Point endValue) {            int startX = startValue.getPointX();            int endX = endValue.getPointX();            int reslut = (int) (startX + (endX - startX) * fraction);            Point point = new Point(reslut);            return point;        }    }}

    开启动画

    pointView.startAnimator();

3、AnimatorSet

AnimatorSet animatorSet = new AnimatorSet() ;ObjectAnimator animator1 = ObjectAnimator.ofFloat(testBtn,"translationX",200);ObjectAnimator animator2 = ObjectAnimator.ofFloat(testBtn,"translationY",200);animatorSet.play(animator1);animatorSet.playSequentially(animator1,animator2);//依次执行动画animatorSet.playTogether(animator1,animator2);//同时执行动画animatorSet.setDuration(500);animatorSet.start();

三、矢量动画

1、SVG

svg导出VectorDrawable:http://inloop.github.io/svg2android/

svg在线编辑器http://www.zhangxinxu.com/sp/svg/

Path指令

  • M = moveto(M X,Y) :将画笔移动到指定的坐标位置
  • L = lineto(L X,Y) :画直线到指定的坐标位置
  • H = horizontal lineto(H X):画水平线到指定的X坐标位置
  • V = vertical lineto(V Y):画垂直线到指定的Y坐标位置
  • C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次贝赛曲线
  • S = smooth curveto(S X2,Y2,ENDX,ENDY)
  • Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次贝赛曲线
  • T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射
  • A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线
  • Z = closepath():关闭路径

大写绝对定位,参照全局坐标系;小写相对定位

通过一个实例演示SVG动画实现

  • 定义VectorDrawable

    search_bar.xml

    <?xml version="1.0" encoding="utf-8"?><vector xmlns:android="http://schemas.android.com/apk/res/android"    android:width="150dp"    android:height="24dp"    android:viewportWidth="150"    android:viewportHeight="24">    <!-- 搜索按钮-->    <path        android:name="search"        android:pathData="M141,17 A9,9 0 1,1 142,16 L149,23"        android:strokeWidth="2"        android:strokeColor="#ffffff"        android:strokeAlpha="0.8"        android:strokeLineCap="round" />    <!-- 底部线条 -->    <path        android:name="bar"        android:pathData="M0,23 L149,23"        android:strokeWidth="2"        android:strokeColor="#ffffff"        android:strokeAlpha="0.8"        android:strokeLineCap="square" /></vector>

    上述search_bar.xml定义在drawable文件夹下,可以在Android Studio中直接预览结果

  • 定义animated-vector

    animated-vector相当于一个桥梁,将动画与VectorDrawable连接在一起

    search_to_bar.xml

    <?xml version="1.0" encoding="utf-8"?><animated-vector    xmlns:android="http://schemas.android.com/apk/res/android"    android:drawable="@drawable/search_bar">    <target        android:animation="@animator/anim_search_none"        android:name="search" />    <target        android:animation="@animator/anim_bar_fill"        android:name="bar" /></animated-vector>

    bar_to_search.xml

    <?xml version="1.0" encoding="utf-8"?><animated-vector     xmlns:android="http://schemas.android.com/apk/res/android"    android:drawable="@drawable/search_bar" >    <target        android:animation="@animator/anim_search_fill"        android:name="search"/>    <target        android:animation="@animator/anim_bar_none"        android:name="bar"/></animated-vector>
  • 定义动画

    anim_bar_fill.xml(显示bar)

    <?xml version="1.0" encoding="utf-8"?><objectAnimator    xmlns:android="http://schemas.android.com/apk/res/android"    android:propertyName="trimPathEnd"    android:valueFrom="0"    android:valueTo="1"    android:valueType="floatType"    android:duration="500" />

    anim_bar_none.xml(将bar隐藏)

    <?xml version="1.0" encoding="utf-8"?><objectAnimator    xmlns:android="http://schemas.android.com/apk/res/android"    android:propertyName="trimPathEnd"    android:valueFrom="1"    android:valueTo="0"    android:valueType="floatType"    android:duration="500" />

    anim_search_fill.xml(显示搜索按钮)

    <?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="500"    android:propertyName="trimPathEnd"    android:valueFrom="0"    android:valueTo="1"    android:valueType="floatType" />

    anim_search_none.xml(隐藏搜索按钮)

    <?xml version="1.0" encoding="utf-8"?><objectAnimator    xmlns:android="http://schemas.android.com/apk/res/android"    android:propertyName="trimPathEnd"    android:valueFrom="1"    android:valueTo="0"    android:valueType="floatType"    android:duration="500" />
  • 使用

    public class SvgActivity extends AppCompatActivity {    private ImageView search ;    private Boolean flag = false ;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_svg);        search = (ImageView) findViewById(R.id.search);        final AnimatedVectorDrawable barToSearch = (AnimatedVectorDrawable) getResources().getDrawable(R.drawable.bar_to_search);        final AnimatedVectorDrawable searchToBar = (AnimatedVectorDrawable) getResources().getDrawable(R.drawable.search_to_bar);        search.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if(flag) {                    search.setImageDrawable(barToSearch);                    barToSearch.start();                    flag = false ;                }else {                    search.setImageDrawable(searchToBar);                    searchToBar.start();                    flag = true ;                }            }        });    }}
原创粉丝点击