Android动画小结

来源:互联网 发布:c51单片机引脚图 编辑:程序博客网 时间:2024/05/16 16:06

属性动画总结

Property Animation:属性动画是针对于3.0(API 11)以上版本的系统有效;
动画特点:可以设置给任意的Object,包括还没有渲染到屏幕上的对象;
可扩展性:自定义任何类型和属性的动画;

常用的View属性成员:

  • translationX,translationY:控制View的位置,值是相对于View容器左上角坐标的偏移;
  • rotationX,rotationY:控制相当于轴心得旋转;
  • x,y:控制View在在容器中的位置,即左上角坐标加上translationX和translationY的值;
  • alpha:控制View对象的alpha透明度值;

属性动画概述:

/** * This is the superclass for classes which provide basic support for animations which can be * started, ended, and have <code>AnimatorListeners</code> added to them. */public abstract class Animator implements Cloneable {    ......}

所有属性动画的BaseClass就是Animator这个抽象类;

由Animator派生出来的类之间的关系:(我们能看到:AnimatorSet 和ValueAnimator是直接子类,实际我们使用的单个动画效果的时候使用的是ObjectAnimator,ObjectAnimator是ValueAnimator的直接子类,关于ValueAnimator的作用和使用稍后分析,关于TimeAnimator本人使用比较少)
这里写图片描述

属性动画的属性:

  • Duration:动画的持续时间;
  • TimeInterpolation:定义动画变化速率的接口,这个接口是所有插值器的规范,像线性插值器、非线性插值器都得实现此接口。
  • TypeEvaluator:用于定义属性值计算方式的接口,有int、float、color类型,根据属性的起始、结束值、和差值一起计算出当前时间的属性值。

以上扯了那么多用的,其实属性动画就是Animator,补间动画就是Animation先记住这么多区别熟练运用之后再去尝试理解它的设计模式,底层实现方式

    /**     * 旋转     * @param view     */    public void rotateAnimator(View view){        ObjectAnimator.ofFloat(view,"rotationX",50f,95f)                .setDuration(3000)                .start();//x轴的话默认的就是出于0度,往屏幕里面的方向转的    }

对于ObjectAnimator:提供的几个方法,提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。当对于属性值,只设置一个的时候,会认为当然对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束~~~

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

所以对于我们自定以的View或者说对于控件的设置某一个属性值的方法中并没有重新绘制View的操作,我们就需要自己写代码去更新视图的操作:

anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator valueAnimator) {                        view.invalidate();                        view.postInvalidate();                    }                })

在不是用AnimatorSet的情况下如何设置多个属性同时变化:

public void rotateAnimator(final View view){        ObjectAnimator anim = ObjectAnimator.ofFloat(view,"abc",1.0f,0f)                .setDuration(1000);//这里的abc属性是随便写的 ,因为我们要使用的是ValueAnimator //每一个ObjectAnimator都有一个ValueAnimator,很明先就是指值的变化        anim.start();        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator valueAnimator) {                float cVal = (float) valueAnimator.getAnimatedValue();                view.setAlpha(cVal);                view.setScaleX(cVal);                view.setScaleY(cVal);            }        });    }//从之前的解释我们知道,属性动画是不断的刷新来重新为View设置新的值来达到动画的效果的

实现一个动画更改多个效果:使用propertyValuesHolder

public void rotateAnimator(final View view){        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha",1f,0f,1f);//这里后面的值是可以赋多个值的,        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX",1f,0f,1f);        PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY",1f,0f,1f);        ObjectAnimator.ofPropertyValuesHolder(view,pvhX,pvhY,pvhZ).setDuration(1000).start();//同理这里的holder中也可以同时放进去多个holder    }

接下来看一下和ValueAnimator的用法,简单看一下用view垂直移动的动画代码

 public void rotateAnimator(final View view){        ValueAnimator animator = ValueAnimator.ofFloat(1.0f,0f);        animator.setTarget(view);        animator.setDuration(1000);        animator.start();        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator valueAnimator) {                view.setScaleY((Float) valueAnimator.getAnimatedValue());            }        });    }//这里的和ObjectAnimator的区别就是没有设置属性值,属性值的更改是在监听事件中进行的,所以好处就是我们不需要关心这个属性值是够有get和set方法

TypeEvaluator的用法

public void rotateAnimator(final View view){        ValueAnimator valueAnimator = new ValueAnimator();        valueAnimator.setDuration(3000);        valueAnimator.setObjectValues(new PointF(0,0));        valueAnimator.setInterpolator(new LinearInterpolator());        valueAnimator.setEvaluator(new TypeEvaluator<PointF>(){            @Override            public PointF evaluate(float v, PointF pointF, PointF t1) {                Log.i("TAG",200 * v * 3+"");                PointF point = new PointF();                point.x = 200 * v * 3;//此时x的值就是在0-600之间均匀的增加的  至于速率是多少我也暂时不知道                point.y = 0.5f * 200 * (v * 3) * (v * 3);//这里的v就相当于是自变量x从0-1变化所以y的值就类似于900*x的平方                return point;            }        });        valueAnimator.start();        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator valueAnimator) {                PointF point = (PointF) valueAnimator.getAnimatedValue();                //这里可以获取得到PointF中的值x和y对要操作的控件进行赋值操作了            }        });    }  //这里我们为什么要使用这种方式也很明显 因为x和y的值要同时变化,ofInt和ofFloat就不能使用,所以我们自定义一种TypeEvaluator,如果两个参数仍然不够使用的话我们可以自定义一个Bean作为泛型传递进去就ok

动画的监听事件:

ObjectAnimator animator = ObjectAnimator.ofFloat(view,"alpha",0.5f);//只有一个参数的就是代表初始值        animator.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) {                //动画取消的            }        });  //对于之上的方法太长 要复写所有的方法,我们可以使用AnimatorListenerAdapter 去实现其中的一个方法就可以

AnimatorSet的使用

  ObjectAnimator animator1 = ObjectAnimator.ofFloat(view,"alpha",0.5f);        ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,"translateX",0.5f);        AnimatorSet animatorSet = new AnimatorSet();        animatorSet.playTogether(animator1,animator2);        //或者        animatorSet.play(animator1).with(animator2);        animatorSet.setDuration(1000);        animatorSet.setInterpolator(new LinearInterpolator());        animatorSet.start();

以上是使用代码来实现动画,下面是使用xml文件加载出来动画

1.文件路径 res/animator/动画xml文件

先看一个最简单的:

<?xml version="1.0" encoding="utf-8"?><objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="1000"    android:propertyName="scaleX"    android:valueFrom="1.0"    android:valueTo="2.0"    android:valueType="floatType"></objectAnimator> Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scalex);        animator.setTarget(view);        animator.start();

动画集合的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.0"        android:valueTo="0.5"        android:valueType="floatType"/>    <objectAnimator        android:duration="1000"        android:propertyName="scaleY"        android:valueFrom="1.0"        android:valueTo="0.5"        android:valueType="floatType"/></set>

在Activity中的实现了上面没什么区别

  Animator animator = AnimatorInflater.loadAnimator(this, R.animator.myset);        animator.setTarget(view);        animator.start();

关于布局动画的实现方式:主要是通过LayoutTransition来实现

  1. APPEARING ——元素在容器中显示时需要动画显示
  2. CHANGE_APPEARING——由于容器中要显示一个新的元素,其他元素的变化需要动画显示
  3. DISAPPERARING——元素在容器中消失时需要动画
  4. CHANGE_DISAPPERARING——由于容器中某个元素要消失,其他元素的变化需要动画显示

一个布局动画的Demo提供参考

package com.example.administrator.animatortest;import android.animation.Animator;import android.animation.AnimatorInflater;import android.animation.AnimatorListenerAdapter;import android.animation.AnimatorSet;import android.animation.Keyframe;import android.animation.LayoutTransition;import android.animation.ObjectAnimator;import android.animation.PropertyValuesHolder;import android.animation.TypeEvaluator;import android.animation.ValueAnimator;import android.graphics.Color;import android.graphics.PointF;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.animation.LinearInterpolator;import android.widget.Button;import android.widget.GridLayout;import android.widget.LinearLayout;public class MainActivity extends AppCompatActivity implements View.OnClickListener{    private Button mButtonAdd;    private Button mButtonReset;    private GridLayout mGridLayout;    private int buttonNumbers = 1;    private LayoutTransition mLayoutTransition;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mButtonAdd = (Button) findViewById(R.id.layout_animator_addbutton);        mButtonAdd.setOnClickListener(this);        mButtonReset = (Button) findViewById(R.id.layout_animator_resetbutton);        mButtonReset.setOnClickListener(this);        mGridLayout = (GridLayout) findViewById(R.id.layout_animator_gridview);        //为GridView设置LayoutTransition对象        mLayoutTransition = new LayoutTransition();        mGridLayout.setLayoutTransition(mLayoutTransition);        mLayoutTransition.setDuration(300);        mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING,30);        mLayoutTransition.setStagger(LayoutTransition.CHANGE_DISAPPEARING,30);        //和setStagger的区别就是setStagger是通过第一个参数来作为条件单独为这种情况下设置动画时间        //所以duration是要放在前面的说  不然放在后面 就把之前的属性重新覆盖了        //初始化自定义的动画效果        customLayoutTransition();    }    /**     * 自定义效果     */    private void customLayoutTransition() {        //这里的话是为出现的View设置的动画效果        ObjectAnimator mAnimatorAppearing = ObjectAnimator.                ofFloat(null,"rotationY",90.0f,0.0f)                .setDuration(mLayoutTransition.getDuration(LayoutTransition.APPEARING));//添加的动画时间        //为LayoutTransition设置动画和类型        mLayoutTransition.setAnimator(LayoutTransition.APPEARING,mAnimatorAppearing);        /**         * Add Button         * LayoutTransition.CHANGE_APPEARING         * 当增加一个Button时,设置其他Button的动画效果         */        PropertyValuesHolder pvhLeft =                PropertyValuesHolder.ofInt("left", 0, 1);        PropertyValuesHolder pvhTop =                PropertyValuesHolder.ofInt("top", 0, 1);        PropertyValuesHolder pvhRight =                PropertyValuesHolder.ofInt("right", 0, 1);        PropertyValuesHolder pvhBottom =                PropertyValuesHolder.ofInt("bottom", 0, 1);        PropertyValuesHolder mHolderScaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f,0.0f,1.0f);        PropertyValuesHolder mHolderScaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f,0.0f,1.0f);        ObjectAnimator mObjectAnimatorChangeAppearing = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft,                pvhTop,pvhRight,pvhBottom,mHolderScaleX,mHolderScaleY).setDuration(mLayoutTransition                .getDuration(LayoutTransition.CHANGE_APPEARING));        mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, mObjectAnimatorChangeAppearing);        mObjectAnimatorChangeAppearing.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                // TODO Auto-generated method stub                super.onAnimationEnd(animation);                View view = (View) ((ObjectAnimator) animation).getTarget();                view.setScaleX(1f);                view.setScaleY(1f);            }        });        /**         * Delete Button         * LayoutTransition.DISAPPEARING         * 当删除一个Button时,设置该Button的动画效果         */        ObjectAnimator mObjectAnimatorDisAppearing = ObjectAnimator.ofFloat(null, "rotationX", 0.0f,90.0f)                .setDuration(mLayoutTransition.getDuration(LayoutTransition.DISAPPEARING));        mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, mObjectAnimatorDisAppearing);        mObjectAnimatorDisAppearing.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                // TODO Auto-generated method stub                super.onAnimationEnd(animation);                View view = (View) ((ObjectAnimator) animation).getTarget();                view.setRotationX(0.0f);            }        });        /**         * Delete Button         * LayoutTransition.CHANGE_DISAPPEARING         * 当删除一个Button时,设置其它Button的动画效果         */        //Keyframe 对象中包含了一个时间/属性值的键值对,用于定义某个时刻的动画状态。        Keyframe mKeyframeStart = Keyframe.ofFloat(0.0f, 0.0f);        Keyframe mKeyframeMiddle = Keyframe.ofFloat(0.5f, 180.0f);        Keyframe mKeyframeEndBefore = Keyframe.ofFloat(0.999f, 360.0f);        Keyframe mKeyframeEnd = Keyframe.ofFloat(1.0f, 0.0f);        PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",                mKeyframeStart,mKeyframeMiddle,mKeyframeEndBefore,mKeyframeEnd);        ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft,pvhTop,pvhRight,pvhBottom,mPropertyValuesHolder)                .setDuration(mLayoutTransition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));        mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);        mObjectAnimatorChangeDisAppearing.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                // TODO Auto-generated method stub                super.onAnimationEnd(animation);                View view = (View) ((ObjectAnimator) animation).getTarget();                view.setRotation(0.0f);            }        });    }    /**     * 点击事件     * @param v     */    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.layout_animator_addbutton:                addButton();                break;            case R.id.layout_animator_resetbutton:                resetButton();                break;            default:                break;        }    }    /**     * 删除所有的View重置GridLayout     */    private void resetButton() {        mGridLayout.removeAllViews();        buttonNumbers=1;    }    /**     * 增加一个Button     */    private void addButton() {        Button mButton =  new Button(this);        LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(50,50);        mButton.setLayoutParams(mLayoutParams);        mButton.setText(String.valueOf(buttonNumbers++));        mButton.setTextColor(Color.rgb(0,0,0));        if(buttonNumbers % 2 ==1){            mButton.setBackgroundColor(Color.rgb(45,118,87));        }else {            mButton.setBackgroundColor(Color.rgb(225,24,0));        }        mButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mGridLayout.removeView(v);            }        });        mGridLayout.addView(mButton,Math.min(1,mGridLayout.getChildCount()));//这里使用的是插入的方法 所以添加的话也会导致 其他view的变化    }}布局文件

这个Dmeo 基本上涵盖了属性动画的用法和布局动画的用法,手动敲一下还是能更深入的理解的
0 0
原创粉丝点击