android 里的动画,自己的一些总结

不要抱怨身边的环境,去改变自己,让自己拥有更好的环境。

前言

移动端开发界面有时候要加入一些动画,android里有2类动画,第一类是View动画(View动画里又分2类,一类是帧动画,另一类是补间动画),另一类是属性动画;顾名思义View动画只能操作View对象,但是并不会改变View的属性。如果想要通过动画改变对象的属性值,这时候我们可以考虑使用属性动画来实现效果了。

补间(Tween)动画

透明度(alpha)、缩放(scale)、平移(translate)、旋转(rotate)
透明度(alpha)
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
    android:repeatCount="3"
    android:repeatMode="restart"
    android:fillAfter="true"
    android:duration="2000">
</alpha>

android:fromAlpha 动画开始的透明度,从0.0 –1.0 ,0.0表示全透明,1.0表示完全不透明
android:toAlpha 动画结束时的透明度,也是从0.0 –1.0 ,0.0表示全透明,1.0表示完全不透明

缩放(scale)
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0"
android:fromYScale="0"
android:toXScale="2"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="3"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000" />

android:pivotX 当取50%时:在原点坐标的基础上加上的自己宽度的50%;50:在原点坐标的基础上加上50;50%p:在原点坐标的基础上加上父控件的50%
android:pivotY 缩放起点Y轴坐标,取值及意义跟android:pivotX一样
android:fromXScale 起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍;
android:toXScale 结尾的X方向上相对自身的缩放比例,浮点值;
android:fromYScale 起始的Y方向上相对自身的缩放比例,浮点值,
android:toYScale 结尾的Y方向上相对自身的缩放比例,浮点值;

平移(translate)
<translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromXDelta="100"
        android:fromYDelta="130"
        android:toXDelta="50"
        android:toYDelta="150"
        android:repeatCount="1"
        android:repeatMode="restart"
        android:fillAfter="true"
        android:duration="2000" />

android:fromXDelta 起始点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,具体意义已在scale标签中讲述,这里就不再重讲
android:fromYDelta 起始点Y轴从标,可以是数值、百分数、百分数p 三种样式;
android:toXDelta 结束点X轴坐标
android:toYDelta 结束点Y轴坐标

旋转(rotate)
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="-360"   负数逆时针 正数顺时针
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000" />

android:pivotX 同上
android:pivotY 同上

我们可以发现,透明度(alpha)、缩放(scale)、平移(translate)、旋转(rotate)这四种动画有一些共同的属性:

Animation类继承的属性(因为这4种动画都是继承Animation)

android:repeatCount="1"
android:repeatMode="restart"
android:fillAfter="true"
android:duration="2000"
android:interpolator="@animator/animatortest"
....

android:duration 动画持续时间,以毫秒为单位
android:fillAfter 如果设置为true,控件动画结束时,将保持动画最后时的状态
android:fillBefore 如果设置为true,控件动画结束时,还原到开始动画前的状态
android:fillEnabled 与android:fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
android:repeatCount 重复次数
android:repeatMode 重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。
android:interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等

动画集合(Set)

如果我们想让View进行缩放的动画的同时旋转,再平移,同时透明度也跟着改变;set没有私有的属性,set也继承Animation, set里使用的Animation的所有属性都同时作用与set的字节点。

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fillAfter="true">
    <translate
        android:fromXDelta="0"
        android:toXDelta="-300" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1.0"/>
    <scale
        android:fromXScale="1.0"
        android:toXScale="2.0"
        android:fromYScale="0.0"
        android:toYScale="1.4"
        android:pivotX="50%"
        android:pivotY="50%"/>
    <rotate
        android:fromDegrees="0"
        android:toDegrees="720"
        android:pivotX="50%"
        android:pivotY="50%"/>
</set>

属性值同上面;
但是要注意以set里的属性为主,

怎么在code里使用这些xml定义的动画?
Animation animation = AnimationUtils.loadAnimation(this, R.anim.alphaanim);   // res目录下创建一个anim文件夹
findViewById(R.id.tv_test).startAnimation(animation);  //使用xml 生成动画
如果我们不想使用xml,用代码实现动画。
scale 动画使用代码实现:
ScaleAnimation scaleAnimation = new ScaleAnimation(1, 1, 2, 2);
scaleAnimation.setDuration(1000);
scaleAnimation.setFillEnabled(true);
scaleAnimation.setInterpolator(new BounceInterpolator());   //设置插值器  比如先加速 后减速等

public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
//  构造方法里参数对应着上面的xml实现的动画的属性
        mResources = null;
        mFromX = fromX;
        mToX = toX;
        mFromY = fromY;
        mToY = toY;
        mPivotX = 0;
        mPivotY = 0;
    }

findViewById(R.id.tv_test).startAnimation(animation);  //开始动画
set联合动画使用代码实现:
 AnimationSet setAnim = new AnimationSet(true);
        setAnim.addAnimation(rotateAnim);
        setAnim.addAnimation(scaleAnimation);  //对应上面的scaleAnimation  其他的rotateAnim等同理
        setAnim.addAnimation(translateAnimation);
        setAnim.setDuration(3000);
        setAnim.setFillAfter(true);
        mTvTest.startAnimation(setAnim);

属性(Property Animator)动画

1.Property Animation是API Level 11(Android 3.0)引入的;
2.Property Animator包括ValueAnimator和ObjectAnimator。

属性动画ValueAnimator
 public void testValueAnimator() {
        ValueAnimator animator = ValueAnimator.ofInt(0, 400);
        ValueAnimator.AnimatorUpdateListener animatorUpdateListener;
        animator.addUpdateListener(animatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
            int value = (int) animation.getAnimatedValue();
            }
        });
        animator.setDuration(2000);
        animator.start();
    }

通过注册一个监听方法,int value = (int) animation.getAnimatedValue();得到当前进度的具体值(0-400);还有ofFloat(), ofObject(), ofArgb()等;ofObject()要指定一个TypeEvaluator(这个是将当前进度转为具体值的类); 因为ofInt() ofFloat等系统都有相应的TypeEvaluator,所以不需要我们再指定。

属性动画ObjectAnimator
该动画继承ValueAnimator;
public final class ObjectAnimator extends ValueAnimator
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)
// target: 即将动画的对象;propertyName: 对象要改变的属性;

 public void testObjectAnimatorByTranslationX() {
        //translationX translationY translation  平移
        //alphaX alphaY  透明度
        //rotation rotationX rotationY 旋转
        //scaleX scaleY 缩放
        ObjectAnimator animator = ObjectAnimator.ofFloat(mTvTest, "translationZ", 100, 0, 200);
        animator.setDuration(2000);
        animator.start();
    }
    // mTvTest: TextView对象 在TextView里没有发现setTranslationZ(),最后在他的父类View里面发现了。
     public void setTranslationZ(float translationZ) {
        if (translationZ != getTranslationZ()) {
            invalidateViewProperty(true, false);
            mRenderNode.setTranslationZ(translationZ);
            invalidateViewProperty(false, true); 
            // 动画通过改变translationZ属性值,通过反射得到setTranslationZ方法(String methodName = getMethodName("set", mPropertyName);),进而调用该方法。invalidateViewProperty 重绘View;
            invalidateParentIfNeededAndWasQuickRejected();
        }
    }
我们动画的对象属性没有相应的setter方法,我们可以重写该类,提供对应的属性的setter;

比如我们想对象的pointRadio属性动画:

public class MyView extends View {
    private Point mPoint = new Point(100);
    public MyView(Context context) {
        super(context);
    }
    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        canvas.drawCircle(100, 100, mPoint.getmRadio(), paint);
    }
    public void setPointRadio(int radio) {
        mPoint.setmRadio(radio);
        invalidate();  // 从上面的解释 动画是通过反射调用属性的setter,我们在这里改变属性的值,然后再重绘!
    }
    //如果只给动画设置一个值时,会调用该方法得到 初始值  没有定义该方法  会用默认值 int :0
    public int getPointRadio() {
        return 50;
    }
}

其他api
ofObject等都大同小异;ofObject() 我们通过ValueAnimator知道,要指定一个TypeEvaluator;

TypeEvaluator(评估者)
将动画的进度转为对应的值 这里只贴一个自定义的TypeEvaluator
public class CharEvaluator implements TypeEvaluator<Character> {
    @Override
    public Character evaluate(float fraction, Character startValue, Character endValue) {
    // fraction: 进度值
        int startInt = startValue;
        int endInt = endValue;
        int type =  (int) (startInt + fraction * (endInt - startInt));
        return (char)type;
    }
}
Interpolator(插值器)
控制动画的进度
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;    // input: 表示当前的进度 我们自定义插值器的时候一般实现TimeInterpolator类
/**
abstract public class BaseInterpolator implements Interpolator 
public interface Interpolator extends TimeInterpolator 
public interface TimeInterpolator {
    float getInterpolation(float input);
}
*/
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}
Keyframe(关键帧)
用来指定进度对应的相应属性值,比如我要在动画进行到0.3的时候对应的数值是多少。这样可以取代一些插值器的自定义,他们都是用来控制动画的进度!
public static Keyframe ofObject(float fraction, Object value) 
// fraction: 进度值 value: 当前进度对应的属性值
private void PropertyValuesHolderByOfObject() {
        Keyframe keyframe1 = Keyframe.ofObject(0f, new Character('A'));   // 0f: 动画刚开始的时候
        Keyframe keyframe2 = Keyframe.ofObject(0.1f, new Character('L'));
        Keyframe keyframe3 = Keyframe.ofObject(1f, new Character('Z')); // 1f: 动画结束的时候
        PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("char", keyframe1, keyframe2, keyframe3);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mPropertyView, holder);
        animator.setEvaluator(new CharEvaluator());
        animator.setDuration(3000);
        animator.start();
    }
PropertyValuesHolder
保存动画的属性等信息
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values)
// propertyName: 对象的属性  values:指定当前对象的属性具体的进度对应的数值

PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("char", keyframe1, keyframe2, keyframe3); // 上面介绍了,反射对象的setChar方法 来改变对象的属性;
PropertyValuesHolder怎么被使用?
ValueAnimator,ObjectAnimator都有相应的ofPropertyValuesHolder方法。
public static ObjectAnimator ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)
// target: 要使用动画的对象 values: 可以指定多个属性 进而可以使动画对象的多个属性同时变化,比如我们在平移的时候背景颜色也一同变化。一些情况下可以取代下面介绍的AnimatorSet(联合动画)。
AnimatorSet(联合动画)
 /**
     * playSequentially:依次执行动画
     * playTogether:一起执行动画
     */
public void AnimatorSetByPlaySequentially() {
        ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mTvTest, "translationX", 100, 0, 200);
        ObjectAnimator bgAnimator = ObjectAnimator.ofInt(mPropertyView, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(translationAnimator, bgAnimator);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }

public void AnimatorSetByPlay() {
        //with 一起执行   before 后执行  after 先执行
        ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mTvTest, "translationX", 100, 0, 200);
        ObjectAnimator bgAnimator = ObjectAnimator.ofInt(mPropertyView, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
        AnimatorSet animatorSet = new AnimatorSet();
        AnimatorSet.Builder builder = animatorSet.play(translationAnimator);
        builder.after(bgAnimator); // after 先执行
        animatorSet.setDuration(2000);
        animatorSet.start();
    }
总结
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值