Android中动画之三属性动画高级用法一

一.目的

1.差值器和估值器的概念和介绍

2.ObjectAnimator和ValueAnimator对任意类的任意属性做动画的基本用法

二.差值器和估值器简介

目的:

为下面做准备,弄清概念很重要。

TimeInterpolator :

差值器,根据时间流逝的百分比来计算当前属性改变的百分比;同时他是最顶层的差值器接口。他下面的子类一次是Interpolator接口,BaseInterpolator抽象类,LinearInterpolator等系统带的几个差值器实现类。

TypeEvaluator:

根据当前属性改变的百分比(TimeInterpolator 中计算而来)来计算改变后的属性值。

2.1差值器

使用:

动画类ValueAnimator有public void setInterpolator(TimeInterpolator value)方法,TimeInterpolator :差值器的最顶层接口;不调用此方法则默认使用AccelerateDecelerateInterpolator差值器。

介绍

系统自带有:LinearInterpolator(匀速),AccelerateInterpolator(加速),AccelerateDecelerateInterpolator(先加后减速),DecelerateInterpolator(减速)等几个差值器。

自定义插值器

实现Interpolator接口或者TimeInterpolator只要重写public float getInterpolation(float input)方法。

2.2估值器

使用

动画类ValueAnimator有public void setEvaluator(TypeEvaluator value)方法,TypeEvaluator :估值器的最顶层接口;

介绍:

系统自带有:IntEvaluator(int数值估值器),IntArrayEvaluator(int数组估值器),FloatEvaluator(float估值器),FloatArrayEvaluator(float数组估值器),ArgbEvaluator(argb颜色估值器),RectEvaluator(rect矩形估值器)等实现了TypeEvaluator 接口的实现类。

自定义估值器

实现TypeEvaluator接口重写一个evaluate方法就好了。

三.对任意类的任意属性做动画—–基础

解释:

之所以称为基础,一是因为对已有类做处理,只是不能对现有属性直接使用属性动画;二是使用的是ofInt,ofFloat等使用数值的方法(这样就可以使用系统的估值器了);

注意

对任意类(Object)的任意属性(abc)做动画,想要成功要具备俩个条件:

1.Object必须提供setAbc方法;如果动画的时候没有传递初始化值,那么还要有getAbc方法,因为系统要去取abc属性的初始值(如果不满足这个条件,直接crash);
2.Object的setAbc对属性abc所做的改变必须通过某种方法表现出来,最常见的就是UI的变化。(如果不满足这个条件,不会crash,但是没有效果)

3.1例子

目的:想对现有的View(LinearLayout)的宽度属性进行动画处理

问题:

但是我们发现在直接使用ObjectAnimator ani = ObjectAnimator.ofInt(showLl,"width",100,500);(showLl是LinearLayout)这种写法会报错,我们发现里面没有setWidth方法。同时我们发现VIew中有getWidth方法,且是我们想要的。其他View的子类这里不一一列举,大家可以举一反三。

解决方案:对于这种情况有两种可行的方案:

  1. 用一个类来包装原有类,间接为其提供set和get方法(建议使用这种方法,简单可靠)
  2. 使用ValueAnimator,监听动画过程,自己实现具体的属性的改变

3.1.1使用方案一

用一个类来包装原有类,间接为其提供set和get方法(建议使用这种方法,简单可靠)

先看效果

这里写图片描述

代码

Activity,点击执行动画操作

public class PropertyActivity extends AppCompatActivity {
    private Button playBtn;
    private LinearLayout showLl;
    private TextView showTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_property);

        playBtn = (Button) findViewById(R.id.play_btn);
        showLl = (LinearLayout) findViewById(R.id.show_ll);
        showTv = (TextView) findViewById(R.id.show_tv);

        playBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performAni();
            }
        });
    }

    private void performAni() {
        ViewWrapper viewWrapper = new ViewWrapper(showLl);
        int currentWidth = viewWrapper.getWidth();
        ObjectAnimator ani = ObjectAnimator.ofInt(viewWrapper,"width",currentWidth,200);
        ani.setDuration(4000);
        ani.start();
    }

    //View包装类,重要的是get,set的width方法
    private static class ViewWrapper{
        private View taget;

        public ViewWrapper(View taget){
            this.taget = taget;
        }

        public int getWidth(){
            return taget.getWidth();
        }

        public void setWidth(int width){
            taget.getLayoutParams().width = width;
            taget.requestLayout();
        }
    }

}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/play_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="play"/>

    <LinearLayout
        android:id="@+id/show_ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:background="#ff0000">

        <TextView
            android:id="@+id/show_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#00ff00"
            android:textSize="30sp"
            android:text="ProvertyAnimator"/>
    </LinearLayout>
</RelativeLayout>

我们对LinearLayout的宽度属性做了动画处理,从中我们也可以想到对其他属性进行动画处理也是相同的道理,只是更改ViewWrapper的属性的get和set方法而已,关键是两个方法中具体属性的处理。

3.1.2使用方案二

使用ValueAnimator,监听动画过程,自己实现具体的属性的改变

效果图

和3.1.1中是一模一样的,这里不重复粘贴了。

关键是Activity中代码,而布局文件和3.1.1中也是一样的,这里不贴了。

注意里面的注释是关键点。

public class PropertyActivity extends AppCompatActivity {
    private Button playBtn;
    private LinearLayout showLl;
    private TextView showTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_property);

        playBtn = (Button) findViewById(R.id.play_btn);
        showLl = (LinearLayout) findViewById(R.id.show_ll);
        showTv = (TextView) findViewById(R.id.show_tv);

        playBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performAni();
            }
        });
    }

    //下面是关键点
    private void performAni() {
        //获取初始宽度
        final int currentWidth = showLl.getWidth();
        //构造ValueAnimator,从1到100的int动画(这里的1和100可以随意得去取值不一定这俩值)
        final ValueAnimator ani = ValueAnimator.ofInt(1,100);

        //添加监听
        ani.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            //使用系统自带的估值器IntEvaluator
            IntEvaluator intEvaluator = new IntEvaluator();

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //currentValue是ValueAnimator的1到100中的某个值
                int currentValue = (int) animation.getAnimatedValue();
                Log.e("currentValue",currentValue+"");

                //关键点:获取差值器计算所得值(进度百分比0到1)
                float f = animation.getAnimatedFraction();
                //利用intEvaluator来进行估值操作
                showLl.getLayoutParams().width = intEvaluator.evaluate(f,currentWidth,200);
                showLl.requestLayout();
            }
        });

        ani.setDuration(4000).start();
    }
}

猜你喜欢

转载自blog.csdn.net/gongxiaoou/article/details/80745175