android 动画进阶

#Android进阶--动画

##Android进阶路线图 

##一、Android基础动画 ###1、平移动画Translation

  • a、 xml方式实现

    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);

</translate>

  • 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方式实现

    anim_list.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>

    布局

    <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 ;
                    }
                }
            });
        }
    }

###2、Path

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值