深入浅析安卓动画体系

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"/>
    

    获取背景

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

    //创建一个AnimationDrawable
    AnimationDrawable 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);//setTranslationX
animator.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();

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

    //默认是LinearInterpolator
    animator.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 默认使用IntEvaluator
    animator.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 ;
                    }
                }
            });
        }
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值