Android -- Property Animation

简介:

3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:property animation,这三种动画模式在SDK中被称为property animation,view animation,drawable animation。

相关API

  • Property Animation故名思议就是通过动画的方式改变对象的属性了,我们首先需要了解几个属性:
  • Duration动画的持续时间,默认300ms。
  • Time interpolation:时间差值,乍一看不知道是什么,但是我说LinearInterpolator、AccelerateDecelerateInterpolator,大家一定知道是干嘛的了,定义动画的变化率。
  • Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。
  • Animator sets: 动画集合,你可以定义一组动画,一起执行或者顺序执行。
  • Frame refresh delay:帧刷新延迟,对于你的动画,多久刷新一次帧;默认为10ms,但最终依赖系统的当前状态;基本不用管。

 

  • ObjectAnimator  动画的执行类,后面详细介绍
  • ValueAnimator 动画的执行类,后面详细介绍
  • AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。
  • AnimatorInflater 用户加载属性动画的xml文件
  • TypeEvaluator  类型估值,主要用于设置动画操作属性的值。
  • TimeInterpolator 时间插值,上面已经介绍。

ObjectAnimator

复制代码
public class ObjectAnimActivity extends Activity  
{  
    @Override  
    protected void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.xml_for_anim);  
    }  
  
    public void rotateyAnimRun(View view)  
    {  
         ObjectAnimator//  
         .ofFloat(view, "rotationX", 0.0F, 360.0F)//  
         .setDuration(500)//  
         .start();  
    }  
  
}
复制代码

对于ObjectAnimator

1、提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。

当对于属性值,只设置一个的时候,会认为当然对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束

动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法

2、如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。

复制代码
anim.addUpdateListener(new AnimatorUpdateListener()  
        {  
            @Override  
            public void onAnimationUpdate(ValueAnimator animation)  
            {  
//              view.postInvalidate();  
//              view.invalidate();  
            }  
        });
复制代码

3、看了上面的例子,因为设置的操作的属性只有一个,那么如果希望一个动画能够让View既可以缩小、又能够淡出(3个属性scaleX,scaleY,alpha),只使用ObjectAnimator咋弄?可能会说使用AnimatorSet啊,但是偏偏要用一个ObjectAnimator实例实现呢~下面看代码:

复制代码
public void rotateyAnimRun(final View view)  
{  
    ObjectAnimator anim = ObjectAnimator//  
            .ofFloat(view, "alpha", 1.0F,  0.0F)//  
            .setDuration(500);//  
    anim.start();  
    anim.addUpdateListener(new AnimatorUpdateListener()  
    {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation)  
        {  
            float cVal = (Float) animation.getAnimatedValue();  
            view.setAlpha(cVal);  
            view.setScaleX(cVal);  
            view.setScaleY(cVal);  
        }  
    });  
}
复制代码

4、其实还有更简单的方式,实现一个动画更改多个效果:使用propertyValuesHolder

复制代码
public void propertyValuesHolder(View view)  
    {  
        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,  
                0f, 1f);  
        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,  
                0, 1f);  
        PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,  
                0, 1f);  
        ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();  
    }
复制代码

ValueAnimator

ValueAnimator可以说是整个属性动画框架的核心类,动画的驱动就是在此类中实现的。下面举一个ValueAnimator的实例:

复制代码
ValueAnimator anim= ValueAnimator.ofInt(0, 40);  
animation.setDuration(40);  
animation.start();  
anim.addUpdateListener(new AnimatorUpdateListener() {  
    @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
                //frameValue是通过startValue和endValue以及Fraction计算出来的  
        int frameValue = (Integer)animation.getAnimatedValue();  
        //利用每一帧返回的值,可以做一些改变View大小,坐标,透明度等等操作  
    }  
});
复制代码

ValueAnimator的区别之处:ValueAnimator并没有在属性上做操作,你可能会问这样有啥好处?我岂不是还得手动设置?

好处:不需要操作的对象的属性一定要有getter和setter方法,你可以自己根据当前动画的计算值,来操作任何属性。

复制代码
/** 
     * 落体 
     * @param view 
     */  
    public void verticalRun( View view)  
    {  
        ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight  - mBlueBall.getHeight());  
        animator.setTarget(mBlueBall);  
        animator.setDuration(1000).start();  
        animator.addUpdateListener(new AnimatorUpdateListener()  
        {  
            @Override  
            public void onAnimationUpdate(ValueAnimator animation)  
            {  
                mBlueBall.setTranslationY((Float) animation.getAnimatedValue());  
            }  
        });  
    }
复制代码

与ObjectAnimator不同的就是我们自己设置元素属性的更新,虽然多了几行代码,但是貌似提高灵活性。

下面再来一个例子,如果我希望小球抛物线运动【实现抛物线的效果,水平方向100px/s,垂直方向加速度200px/s*s 】,分析一下,貌似只和时间有关系,但是根据时间的变化,横向和纵向的移动速率是不同的,我们该咋实现呢?此时就要重写TypeValue的时候了,因为我们在时间变化的同时,需要返回给对象两个值,x当前位置,y当前位置:

复制代码
/** 
     * 抛物线 
     * @param view 
     */  
    public void paowuxian(View view)  
    {  
  
        ValueAnimator valueAnimator = new ValueAnimator();  
        valueAnimator.setDuration(3000);  
        valueAnimator.setObjectValues(new PointF(0, 0));  
        valueAnimator.setInterpolator(new LinearInterpolator());  
        valueAnimator.setEvaluator(new TypeEvaluator<PointF>()  
        {  
            // fraction = t / duration  
            @Override  
            public PointF evaluate(float fraction, PointF startValue,  
                    PointF endValue)  
            {  
                Log.e(TAG, fraction * 3 + "");  
                // x方向200px/s ,则y方向0.5 * 10 * t  
                PointF point = new PointF();  
                point.x = 200 * fraction * 3;  
                point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);  
                return point;  
            }  
        });  
  
        valueAnimator.start();  
        valueAnimator.addUpdateListener(new AnimatorUpdateListener()  
        {  
            @Override  
            public void onAnimationUpdate(ValueAnimator animation)  
            {  
                PointF point = (PointF) animation.getAnimatedValue();  
                mBlueBall.setX(point.x);  
                mBlueBall.setY(point.y);  
  
            }  
        });  
    }
复制代码

好了,我们已经分别讲解了ValueAnimator和ObjectAnimator实现动画;二者区别;如何利用部分API,自己更新属性实现效果;自定义TypeEvaluator实现我们的需求;但是我们并没有讲如何设计插值,其实我觉得把,这个插值默认的那一串实现类够用了。

AnimatorSet

复制代码
public void togetherRun(View view)  
    {  
        ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX",  
                1.0f, 2f);  
        ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY",  
                1.0f, 2f);  
        AnimatorSet animSet = new AnimatorSet();  
        animSet.setDuration(2000);  
        animSet.setInterpolator(new LinearInterpolator());  
        //两个动画同时执行  
        animSet.playTogether(anim1, anim2);  
        animSet.start();  
    }  
  
    public void playWithAfter(View view)  
    {  
        float cx = mBlueBall.getX();  
  
        ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX",  
                1.0f, 2f);  
        ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY",  
                1.0f, 2f);  
        ObjectAnimator anim3 = ObjectAnimator.ofFloat(mBlueBall,  
                "x",  cx ,  0f);  
        ObjectAnimator anim4 = ObjectAnimator.ofFloat(mBlueBall,  
                "x", cx);  
          
        /** 
         * anim1,anim2,anim3同时执行 
         * anim4接着执行 
         */  
        AnimatorSet animSet = new AnimatorSet();  
        animSet.play(anim1).with(anim2);  
        animSet.play(anim2).with(anim3);  
        animSet.play(anim4).after(anim3);  
        animSet.setDuration(1000);  
        animSet.start();  
    }  
}
复制代码
  1. 使用playTogether两个动画同时执行,当然还有playSequentially依次执行~~
  2. 如果我们有一堆动画,如何使用代码控制顺序,比如1,2同时;3在2后面;4在1之前等~就是效果2了

有一点注意:animSet.play().with();也是支持链式编程的,但是不要想着狂点,比如 animSet.play(anim1).with(anim2).before(anim3).before(anim5); 这样是不行的,系统不会根据你写的这一长串来决定先后的顺序,所以麻烦你按照上面例子的写法,多写几行。

使用xml文件来创建属性动画

复制代码
<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:ordering="together" >  
  
    <objectAnimator  
        android:duration="1000"  
        android:propertyName="scaleX"  
        android:valueFrom="1"  
        android:valueTo="0.5" >  
    </objectAnimator>  
    <objectAnimator  
        android:duration="1000"  
        android:propertyName="scaleY"  
        android:valueFrom="1"  
        android:valueTo="0.5" >  
    </objectAnimator>  
  
</set>
复制代码
复制代码
public void scaleX(View view)  
    {  
        // 加载动画  
        Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex);  
        anim.setTarget(mMv);  
        anim.start();  
    }
复制代码

使用AnimatorInflater加载动画的资源文件,然后设置目标。

使用set标签,有一个orderring属性设置为together,还有另一个值:sequentially(表示一个接一个执行)。

#忽略了一个效果,就是缩放、反转等都有中心点或者轴,默认中心缩放,和中间对称线为反转线,所以我决定这个横向,纵向缩小以左上角为中心点:

复制代码
// 加载动画  
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scale);  
mMv.setPivotX(0);  
mMv.setPivotY(0);  
//显示的调用invalidate  
mMv.invalidate();  
anim.setTarget(mMv);  
anim.start();
复制代码

很简单,直接给View设置pivotX和pivotY,然后调用一下invalidate,就ok了。

Layout Animations

主要使用LayoutTransition为布局的容器设置动画,当容器中的视图层次发生变化时存在过渡的动画效果。

复制代码
LayoutTransition transition = new LayoutTransition();  
    transition.setAnimator(LayoutTransition.CHANGE_APPEARING, transition.getAnimator(LayoutTransition.CHANGE_APPEARING));  
    transition.setAnimator(LayoutTransition.APPEARING, null);  
    transition.setAnimator(LayoutTransition.DISAPPEARING, null);  
    transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,  null);  
    mGridLayout.setLayoutTransition(transition);
复制代码

过渡的类型一共有四种:

LayoutTransition.APPEARING 当一个View在ViewGroup中出现时,对此View设置的动画

LayoutTransition.CHANGE_APPEARING 当一个View在ViewGroup中出现时,对此View对其他View位置造成影响,对其他View设置的动画

LayoutTransition.DISAPPEARING  当一个View在ViewGroup中消失时,对此View设置的动画

LayoutTransition.CHANGE_DISAPPEARING 当一个View在ViewGroup中消失时,对此View对其他View位置造成影响,对其他View设置的动画

LayoutTransition.CHANGE 不是由于View出现或消失造成对其他View位置造成影响,然后对其他View设置的动画。

注意动画到底设置在谁身上,此View还是其他View。

复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:id="@+id/id_container"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  
  
    <Button  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:onClick="addBtn"  
        android:text="addBtns" />  
  
    <CheckBox  
        android:id="@+id/id_appear"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:checked="true"  
        android:text="APPEARING" />  
  
    <CheckBox  
        android:id="@+id/id_change_appear"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:checked="true"  
        android:text="CHANGE_APPEARING" />  
  
    <CheckBox  
        android:id="@+id/id_disappear"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:checked="true"  
        android:text="DISAPPEARING" />  
  
    <CheckBox  
          android:id="@+id/id_change_disappear"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:checked="true"  
        android:text="CHANGE_DISAPPEARING " />  
  
</LinearLayout>
复制代码
复制代码
public class LayoutAnimaActivity extends Activity implements  OnCheckedChangeListener  {  
    private ViewGroup viewGroup;  
    private GridLayout mGridLayout;  
    private int mVal;  
    private LayoutTransition mTransition;  
  
    private CheckBox mAppear, mChangeAppear, mDisAppear, mChangeDisAppear;  
  
    @Override  
    public void onCreate(Bundle savedInstanceState)  {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.layout_animator);  
        viewGroup = (ViewGroup) findViewById(R.id.id_container);  
  
        mAppear = (CheckBox) findViewById(R.id.id_appear);  
        mChangeAppear = (CheckBox) findViewById(R.id.id_change_appear);  
        mDisAppear = (CheckBox) findViewById(R.id.id_disappear);  
        mChangeDisAppear = (CheckBox) findViewById(R.id.id_change_disappear);  
  
        mAppear.setOnCheckedChangeListener(this);  
        mChangeAppear.setOnCheckedChangeListener(this);  
        mDisAppear.setOnCheckedChangeListener(this);  
        mChangeDisAppear.setOnCheckedChangeListener(this);  
  
        // 创建一个GridLayout  
        mGridLayout = new GridLayout(this);  
        // 设置每列5个按钮  
        mGridLayout.setColumnCount(5);  
        // 添加到布局中  
        viewGroup.addView(mGridLayout);  
        //默认动画全部开启  
        mTransition = new LayoutTransition();  
        mGridLayout.setLayoutTransition(mTransition);  
  
    }  
  
    /** 
     * 添加按钮 
     *  
     * @param view 
     */  
    public void addBtn(View view)  {  
        final Button button = new Button(this);  
        button.setText((++mVal) + "");  
        mGridLayout.addView(button, Math.min(1, mGridLayout.getChildCount()));  
        button.setOnClickListener(new OnClickListener()  {  
  
            @Override  
            public void onClick(View v) {  
                mGridLayout.removeView(button);  
            }  
        });  
    }  
  
    @Override  
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)  {  
        mTransition = new LayoutTransition();  
        mTransition.setAnimator(   LayoutTransition.APPEARING,   (mAppear.isChecked() ? mTransition  .getAnimator(LayoutTransition.APPEARING) : null));  
        mTransition  .setAnimator( LayoutTransition.CHANGE_APPEARING,  (mChangeAppear.isChecked() ? mTransition.getAnimator(LayoutTransition.CHANGE_APPEARING)  : null));  
        mTransition.setAnimator(  LayoutTransition.DISAPPEARING,   (mDisAppear.isChecked() ? mTransition .getAnimator(LayoutTransition.DISAPPEARING) : null));  
        mTransition.setAnimator(  LayoutTransition.CHANGE_DISAPPEARING,  (mChangeDisAppear.isChecked() ? mTransition  .getAnimator(LayoutTransition.CHANGE_DISAPPEARING)  : null));  
        mGridLayout.setLayoutTransition(mTransition);  
    }  
}
复制代码

1

一定要注意,是对当前View还是其他Views设置的动画。

animate()

复制代码
public void viewAnim(View view)  
    {  
        // need API12  
        mBlueBall.animate()//  
                .alpha(0)//  
                .y(mScreenHeight / 2).setDuration(1000)  
                // need API 12  
                .withStartAction(new Runnable(){  
                    @Override  
                    public void run(){  
                        Log.e(TAG, "START");  
                    }  
                    // need API 16  
                }).withEndAction(new Runnable(){  
  
                    @Override  
                    public void run(){  
                        Log.e(TAG, "END");  
                        runOnUiThread(new Runnable(){  
                            @Override  
                            public void run()  
                            {  
                                mBlueBall.setY(0);  
                                mBlueBall.setAlpha(1.0f);  
                            }  
                        });  
                    }  
                }).start();  
    }
复制代码

简单的使用mBlueBall.animate().alpha(0).y(mScreenHeight / 2).setDuration(1000).start()就能实现动画~~不过需要SDK11,此后在SDK12,SDK16又分别添加了withStartAction和withEndAction用于在动画前,和动画后执行一些操作。当然也可以.setListener(listener)等操作。

使用ObjectAnimator实现上面的变化,我们可以使用:PropertyValueHolder

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,  0f, 1f);  
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 0,   mScreenHeight / 2, 0);  
ObjectAnimator.ofPropertyValuesHolder(mBlueBall, pvhX, pvhY).setDuration(1000).start();

效果与上面一样。

我是天王盖地虎的分割线




本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/4492220.html,如需转载请自行联系原作者

相关文章
|
10月前
|
XML Java Android开发
|
10月前
|
XML Android开发 数据格式
|
XML API Android开发
Android 属性动画Property Animation(中)
ValueAnimator指定整形、浮点型或者颜色值作为动画值,在一定时间内平滑过渡。可以通过ofInt(),ofFloat(),或ofObject()来或得一个ValueAnimator
This project uses AndroidX dependencies, but the ‘android.useAndroidX‘ property is not enabled
This project uses AndroidX dependencies, but the ‘android.useAndroidX‘ property is not enabled
56 0
|
Android开发
Android Animation动画
Android Animation动画
123 0
Android Animation动画
|
Android开发
Animation插值器:解决Android Animation 循环执行的停顿问题
在Android开发中,有时候我们需要一个动画一直循环执行下去,常见的如laoding菊花一直旋转,这时候就需要使用Animation的repeat功能
684 0
|
API Android开发
【Android 属性动画】属性动画 Property Animation 与 视图动画 View Animation 区别
【Android 属性动画】属性动画 Property Animation 与 视图动画 View Animation 区别
110 0
|
XML Java API
Android 属性动画(Property Animation) 完全解析
Android 属性动画(Property Animation) 完全解析
Android 属性动画(Property Animation) 完全解析
This project uses AndroidX dependencies, but the ‘android.useAndroidX‘ property is not enabled
This project uses AndroidX dependencies, but the ‘android.useAndroidX‘ property is not enabled
314 0
|
XML Android开发 数据格式
Android Animation(动画)---基础一
动画分类: 传统动画(帧动画(Frame Animation)/ 补间动画(Tweened Animation))。 属性动画(Attribute Animation) 帧动画 帧动画是将图片一张一张的连续播放,适当的速度,让人感觉是连续的动画。
883 0