Android动画

2021-05-25  本文已影响0人  展翅高飞鹏程万里

帧动画

帧动画在使用时需要注意什么? 问题解释或者解决方案
OOM问题 当图片数量较多且图片较大时就容易出现OOM,这个在实际开发中尤其注意,尽量避免使用帧动画。
内存泄漏 无限循环运行的帧动画,需要在Activity,Fragment,Dialog等对象结束的时候,需要及时停止运行动画

例子:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    <item
        android:drawable="@drawable/a_0"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_1"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_2"
        android:duration="100" />
</animation-list>
protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frame_animation);
        ImageView animationImg1 = (ImageView) findViewById(R.id.animation1);
        animationImg1.setImageResource(R.drawable.frame_anim1);
        AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable();
        animationDrawable1.start();
    }

android:onshot 值为false,解释为循环执行。值为true,解释为一次执行

View补间动画

View动画问题 问题解释或者解决方案
View状态 补间动画只是对View的影像进行操作,并不影响View的实际状态
不要使用px 在进行动画的过程中,要尽量使用dp,使用px会导致在不同的设备上有不同的效果。
硬件加速 使用动画的过程中,建议开启硬件加速,这样子会提高动画的流畅性

在res/anim/文件夹下定义如下的动画实现方式

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
    img = (ImageView) findViewById(R.id.img);
    img.startAnimation(animation);

Interpolator 主要作用是可以控制动画的变化速率 ,就是动画进行的快慢节奏。

pivot 决定了当前动画执行的参考位置

属性动画

属性动画出现的原因? --
Android3.0( API11 )后才提供的一种全新动画模式,出现原因作用于对象限于View,没改变View的属性,动画效果单一
  1. 属性动画View补间动画的区别
    View的补间动画在执行之后并未改变View的真实布局属性值。属性动画弥补了View动画的缺陷,当动画的属性变化时,属性动画会刷新屏幕。属性动画改变的是对象的真实属性,而且属性动画不止用于View,还可以用于任何对象
    private void RotateAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
        anim.setDuration(1000);
        anim.start();
    }

    private void AlpahAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
        anim.setRepeatCount(-1);
        anim.setRepeatMode(ObjectAnimator.REVERSE);
        anim.setDuration(2000);
        anim.start();
    }
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
                ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 0.0f, 1.0f);
                ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 0.0f, 2.0f);
                ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(myView, "rotation", 0, 360);
                ObjectAnimator transXAnim = ObjectAnimator.ofFloat(myView, "translationX", 100, 400);
                ObjectAnimator transYAnim = ObjectAnimator.ofFloat(myView, "tranlsationY", 100, 750);
                AnimatorSet set = new AnimatorSet();
                set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
//              set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
                set.setDuration(3000);
                set.start();

属性动画的原理

属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过度就是由ValueAnimator这个类来负责计算的。他内部使用一种时间循环的机制计算值与值之间的动画过渡。ValueAnimator还负责管理动画的播放次数播放模式以及动画设置监听器等。

因为ValueAnimator可以为任何的对象支持动画操作。那么如何计算startValue到endValue之间的值呢?
ValueAnimator对这种计算过程,抽象成两个层次:

  1. 总时间与计算过程值(差值)之间的比值,也称为动画的完成度(百分数表示。0%表示还未开始,100%表示动画已经执行完成)
  2. 根据当前时间点的动画完成度,针对设置的startValue与endValue,动态计算目标对象的当前时间点的属性值。

TimeInterpolator

TimeInterpolator决定了动画从初始值过渡到结束值的节奏。抽象过程一

public interface TimeIntercepolator {
    /**
    * input: input A value between 0 and 1.0.表示当前动画时间完成度
    * return: 返回值。根据动画时间完成值(客观),二次计算动画时间完成值 (计算:动画的完成度)
    */
    float getInterpolation(float input);
}

例子

<!-- DecelerateInterpolator -->
public float getInterpolation(float input) {    
        float result;
        if (mFactor == 1.0f) {
           result = (float)(1.0f - (1.0f - input) * (1.0f - input));
        } else {
            result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
        }
       return result;
    }
    
<!--
这里使用了两种函数用来计算动画完成的度:
方式一:y = 1 - (1 - x ) * (1 - x )
方式二:y = 1 - (1 - x)^b
涉及到二次函数的走势问题。可参考连接:https://zuotu.91maths.com/
特别说明:方式二中的b常数。b越大函数的走向越陡峭,说明动画执行速度越快,但是整体的加速度占比变短。因为速度太快了,需要花越多时间减速
-->
<!--AccelerateInterpolator-->
public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
}
<!--
这里使用了两种函数用来计算动画完成的度:
方式一:y = x^2
方式二:y = x^b
涉及到二次函数的走势问题。可参考连接:https://zuotu.91maths.com/
特别说明:方式二中的常数b。b越大,一开始的速度越慢,越慢的这种状态的速度占有越久,到后面加速的时速度越快,但时间越短
-->

TypeEvaluator

TypeEvaluator决定了动画如何从初始值过渡到结束值。抽象过程二

public interface TypeEvaluator {

    /**
    * fraction: 表示当前时间点动画完成的百分比。0表示未开始 ,100%表示已经完成
    * startValue:设置动画对象属性的初始值
    * endValue:设置动画对象的结束值
    * /
    @Override
    public abstract Object evaluate(float fraction, Object startValue,Object endValue);
}

例子一

实现目标对象的属性值(类型为Point)从start变化到end的过程

        Point startPoint = (Point) startValue;
        Point endPoint = (Point) endValue;
        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());

        float y = (float) (Math.sin(x * Math.PI / 180) * 100) + endPoint.getY() / 2;
        Point point = new Point(x, y);
        return point;
上一篇 下一篇

猜你喜欢

热点阅读