Android动画-属性动画笔记

什么是属性动画

见名知义,属性动画通过控制对象的属性,(修改控件的属性值)来实现动画效果。属性动画是在Android3.0之后引进的,它非常的强大,可以比较简单的实现许多视图动画做不到的事情。

在使用属性动画之前先来看几个常用的View属性成员:

  • translationX,translationY,translationZ:控制View的位置,值是相对于View容器左上角坐标的偏移。
  • rotationX,rotationY:控制相对于轴心旋转。(0f-> 360f
  • x,y:控制View在容器中的位置,即左上角坐标加上translationX和translationY的值。
  • alpha:控制View对象的alpha透明度值。(0f-> 1f
  • 缩放:水平缩放scaleX,垂直缩放scaleY

ValueAnimator 是ObjectAnimato的父类:

  • ValueAnimator ofInt (int... values):返回一个int型变化的ValueAnimator。
  • ValueAnimator ofFloat (float... values):返回一个float型变化的ValueAnimator。
  • ValueAnimator ofObject (TypeEvaluator evaluator, Object... values):返回一个object型变化的ValueAnimator。
  • ValueAnimator ofArgb (int... values):返回一个颜色值变化的ValueAnimator,API
    LEVEL 21引入。

位移属性动画基本使用

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">

    <LinearLayout
        android:id="@+id/llAddAccount"
        android:layout_width="wrap_content"
        android:layout_height="35dp"
        android:layout_alignParentRight="true"
        android:layout_marginTop="100dp"
        android:layout_marginRight="-70dp"//将现有视图藏在屏幕的右边
        android:background="@drawable/bg_10_10_fff">

        <ImageView
            android:id="@+id/ivMakeNote"
            android:layout_width="35dp"
            android:layout_height="30dp"
            android:layout_gravity="center_vertical"
            android:paddingLeft="2dp"
            android:paddingTop="2dp"
            android:paddingBottom="2dp"
            android:src="@mipmap/ic_account_add" />

        <TextView
            android:id="@+id/tvAddAccount"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:paddingRight="12dp"
            android:text="添加账户"
            android:textColor="@color/colorPrimary"
            android:textSize="14sp" />
    </LinearLayout>
</RelativeLayout>

 mLinearLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ObjectAnimator animator;
                if(!flag){
                    animator = ObjectAnimator.ofFloat(mLinearLayout,"translationX",0f,-70f);
                    flag = true;
                }else {
                    animator = ObjectAnimator.ofFloat(mLinearLayout,"translationX",0f,0f);
                    //animator.setInterpolator(new OvershootInterpolator());
                    flag = false;
                }
                animator.start();
            }
        });

通过ObjectAnimator的工厂方法ofFloat我们得到一个ObjectAnimator对象,并通过该对象的start()方法,开启动画效果。
ofFloat()方法的第一个参数为要实现动画效果的View,例如这里整体效果的LinearLayout;第二个参数为属性名,也就是前面所说的:translationX,translationY,alpha,rotation,scaleX,scaleY等,这里要实现的是水平平移效果,所以我们采用了translationX;第三参数为可变长参数,第一个值为动画开始的位置,第二个值为结束值得位置,如果数组大于3位数,那么前者将是后者的起始位置。
translationXtranslationY这里涉及到的位移都是相对自身位置而言。
例如: View在点A(x,y)要移动到点B(x1,y1),那么ofFloat()方法的可变长参数,第一个值应该0f,第二个值应该x1-x。

XML布局实现:
在res/animator文件夹下,创建animator_translation.xml文件,内容如下:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="translationX"
    android:valueFrom="0dp"
    android:valueTo="-70dp"
    android:valueType="floatType"
/>
 ObjectAnimator animator = AnimatorInflater.loadAnimator(this,R.animator.animator_translation);
 animator.setTarget(mLinearLayout);
 animator.start();

淡入淡出透明属性动画

mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ObjectAnimator objectAnimator  = ObjectAnimator.ofFloat(mTextView,
                        "alpha",1f,0f,1f);
                objectAnimator.setDuration(3000);
                objectAnimator.start();
            }
        });

缩放属性动画基本使用

 //第一个参数是控件,第二个是选择什么动画属性 例如 scaleX(x轴缩放),scaleY
                ObjectAnimator objectAnimator  = ObjectAnimator.ofFloat(mTextView,
                        "scaleX",1f,2f,3f,2f,1f);
                objectAnimator.setDuration(3000);//动画持续时间
                objectAnimator.setRepeatCount(2);//动画重复次数
                objectAnimator.setRepeatMode(ValueAnimator.REVERSE);//动画持续模式 上一次效果反着来
                objectAnimator.start();

旋转属性动画基本使用

  //ofFloat()方法的可变长参数,如果后者的值大于前者,
                // 那么顺时针旋转,小于前者,则逆时针旋转。
                ObjectAnimator objectAnimator  = ObjectAnimator.ofFloat(mTextView,
                        "rotation",0f,180f,0f,-360f,0f);
                objectAnimator.setDuration(3000);//动画持续时间
                objectAnimator.start();

AnimatorSet

代码直接利用 AnimatorSet() 如果是XML定义AnimatorSet 利用AnimatorInflater.loadAnimator()加载(使用较少)

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animator.property_animator);
set.setTarget(mTextView);
set.start();

AnimatorSet可以作用于ObjectAnimator和ValueAnimator,但通常ObjectAnimator用的比较多。

AnimatorSet的相关函数:

  • setInterpolator (TimeInterpolator interpolator),设置之后内部子动画的插值器都是这个
  • setTarget(Object target),设置之后所有内部子动画都作用于相同的target目标对象
  • setStartDelay(long startDelay),它不会覆盖子动画开始延迟,只对AnimatorSet的开始时间起作用,所以它会延后AnimatorSet激活整体动画的开始时间
  • cancle()取消动画,会取消AnimatorSet中的所有子动画。
  • end() 结束动画,会结束AnimatorSet中的所有子动画。
  • getChildAnimations() 获取所有受AnimatorSet控制的动画
  • isStarted(),AnimationSet动画是否开始了,true开始
  • isRunning(),AnimationSet开始之后(isStarted =
    true),内部是否有子动画正在执行,有动画执行返回true
  • pause()暂停动画,
  • resume()恢复暂停的动画
  • play(Animator anim)获取Builder对象

函数 playTogetherplaySequentially的区别:

animatorSet.playTogether(): 多个动画同时执行,可以是对一个对象执行的多个动画,也可以是对多个对象的多个动画。
playTogether(Collection<Animator> items) //利用集合添加动画
playTogether(Animator... items) //利用可变参数添加动画

 ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
                ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
                ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
                ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 50);

                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4);
                animatorSet.setDuration(3000);
                animatorSet.start();
效果和animatorSet.playTogether()差不多
 PropertyValuesHolder holder1=PropertyValuesHolder.ofFloat("rotation",0f,360f,0f);
                PropertyValuesHolder holder2=PropertyValuesHolder.ofFloat("translationX",0f,600f);
                PropertyValuesHolder holder3=PropertyValuesHolder.ofFloat("alpha",1f,0f,1f);
                ObjectAnimator objectAnimator=ObjectAnimator.ofPropertyValuesHolder(sun,holder1,holder2,holder3);
                objectAnimator.setDuration(3000);
                objectAnimator.setInterpolator(new OvershootInterpolator());//插值器
                objectAnimator.start();

如果多个动画同时对控件的同一个属性进行操作,会按照playTogether添加的最后一个动画覆盖前面操作相同属性的动画,也可能没有覆盖,但确实是最后一个添加的动画起了作用。

playSequentially 顺序播放动画:
playSequentially(List<Animator> items)
playSequentially(Animator... items)
playSequentially是一个动画执行完后执行下一个动画,但如果前一个动画是无限循环,下一个动画永远不会执行。

 ObjectAnimator objectAnimator5 = ObjectAnimator.ofFloat(mTextView, "translationY", 200, 450);
                ObjectAnimator objectAnimator6 = ObjectAnimator.ofFloat(mTextView, "translationY", 300, 600);
                ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, "backgroundColor", Color.WHITE, Color.GREEN);
                ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, "scaleX", 0.1f, 1.2f);
                ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, "scaleY", 0.5f, 1.0f);
                ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(mTextView, "translationY", 0, 250);
                AnimatorSet animatorSet = new AnimatorSet();
                //按顺序执行动画
                animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6);
                animatorSet.setDuration(5000);
                animatorSet.start();
  //实现动画无限循环
                objectAnimator1.setRepeatCount(-1);
                animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4,objectAnimator5,objectAnimator6);

利用play(Animator)构建Builder对象

Builder play(Animator anim);生成builder对象,Builder能够控制动画的执行顺序和相互之间的依赖。

Builder的函数:

  • public Builder with(Animator anim) 和前面动画一起执行
  • public Builder before(Animator anim) 执行前面的动画后再执行该动画
  • public Builder after(Animator anim) 先执行这个动画再执行前面动画
  • public Builder after(long delay) 延迟n毫秒之后执行动画
  //按函数性质执行动画
                animatorSet.play(objectAnimator1).with(objectAnimator2).before(objectAnimator3);
                animatorSet.setDuration(5000);
                animatorSet.start();
                   /*
                * 链式调用动画执行顺序总结如下:
                    Builder链式调用中会先执行after函数中的动画(有多个同时执行),
                * 然后执行play和with函数(有多个同时执行)中的动画,
                * 最后执行before函数中的动画(有多个同时执行)
                * */

动画监听
animatorSet.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
        
    }

    @Override
    public void onAnimationEnd(Animator animation) {

    }

    @Override
    public void onAnimationCancel(Animator animation) {

    }

    @Override
    public void onAnimationRepeat(Animator animation) {

    }
});

//需要api19
animatorSet.addPauseListener(new Animator.AnimatorPauseListener() {
    @Override
    public void onAnimationPause(Animator animation) {
        
    }

    @Override
    public void onAnimationResume(Animator animation) {

    }
});

ViewPropertyAnimator 动画

 //ViewPropertyAnimator 动画,只是针对View对象的特定属性同时播放动画
                /*
                * 支持属性:
                    translationX、translationY、translationZ
                    x、y、z
                    alpha
                    scaleX、scaleY
                *
                * */
                mTextView.animate().translationX(100f).translationY(100f).translationZ(20f).
                        setInterpolator(new OvershootInterpolator()).start();
 //ViewPropertyAnimator 动画,只是针对View对象的特定属性同时播放动画
                ViewPropertyAnimator viewPropertyAnimator  = mTextView.animate();
                viewPropertyAnimator.setDuration(2000);
                viewPropertyAnimator.translationX(100f);//点击一次向右偏移,之后点击无效果(一次性)
               //viewPropertyAnimator.translationXBy(100f);//每次点击都会向右偏移,重复利用
                viewPropertyAnimator.start();

估值器与插值器

插值器:根据时间流逝的百分比计算出当前属性值改变的百分比。
正常情况下,默认的插值器已经够用,如果自己数学厉害,想显摆一下,也是通过实现TimeInterpolator接口的getInterpolation()自定义的。
在这里插入图片描述

/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

估值器:根据当前属性改变的百分比来计算改变后的属性值,移动的位置;

自定义估值器:抛物线

//自定义估值器,重写计算规则,多利用数学公式
    class BallDownEvaluator implements TypeEvaluator<PointF>{

        /** * @param fraction 动画执行了的百分比,
         *  * @param startValue 点的起始值 *
         *  @param endValue 点的最终值 * @return
         *  */
        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            //以后可以利用估值器实现更多的曲线动画,比如贝塞尔、正弦余弦动画等。
            //抛物线方程式 s=1/2*g*t*t
            //定义初速度150,加速g=9.8,时间t=5s,就是动画设置的执行时间
            float time = 5* fraction* 1.0f;
            PointF pointF = new PointF();
            pointF.x = 150 * time;
            pointF.y = 0.5f * 98.0f *time *time;
            return pointF;
        }
    }
 mTextView.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onClick(View view) {
                //ValueAnimator 是  ObjectAnimator 的父类
                //太阳下山抛物线
                ObjectAnimator objectAnimator  = new ObjectAnimator();
                BallDownEvaluator ball = new BallDownEvaluator();
                objectAnimator.setDuration(5000);
                //1.先设置value  位置(0,0)
                objectAnimator.setObjectValues(new PointF(0,0));
                //2.再设置估值器
                objectAnimator.setEvaluator(ball);
                objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        PointF pointF = (PointF) valueAnimator.getAnimatedValue();
                        //通过不断的改变view(sun)的坐标来实现抛物线动画
                        sun.setX(pointF.x);
                        sun.setY(pointF.y);
                    }
                });
                objectAnimator.start();
            }
        });

keyFrame(关键帧)

假如觉得自定义自定义插值器或估值器有难度,也可以使用关键帧Keyframe对象来实现。Keyframe让我们可以指定某个属性百分比时对象的属性值。


                Keyframe start = Keyframe.ofFloat(0f,0f);
                Keyframe middle1 = Keyframe.ofFloat(0.3f,300f);
                Keyframe middle2 = Keyframe.ofFloat(0.7f,600f);
                Keyframe end = Keyframe.ofFloat(1f,900f);
                PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",
                        start,middle1,middle2,end);
                ObjectAnimator.ofPropertyValuesHolder(sun,holder).setDuration(3000).start();

链接:各种动画合集
链接:新小梦 https://juejin.cn/post/6846687601118691341

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值