Android animation implementation from basic to custom

1. Basic use

由于是继承了ValueAnimator类
所以使用的方法十分类似:XML 设置 / Java设置

1.1 Java settings

  ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float ....values);  

// Object object: the object to be operated
// String property: the property of the object to be operated
// float ...values: animation initial value & end value (unfixed length)
// If there are two parameters a, b, the animation effect is from the property's a value to the b value // If there are three parameters a,
b, c, the animation effect is from the property's a value to the b value and then to the c value // and so
on

anim.setDuration(500);
        // 设置动画运行的时长

        anim.setStartDelay(500);
        // 设置动画延迟播放时间

        anim.setRepeatCount(0);
        // 设置动画重复播放次数 = 重放次数+1
        // 动画播放次数 = infinite时,动画无限重复

        anim.setRepeatMode(ValueAnimator.RESTART);
        // 设置重复播放动画模式
        // ValueAnimator.RESTART(默认):正序重放
        // ValueAnimator.REVERSE:倒序回放

animator.start();  

// start the animation

1.2 XML settings

    步骤1:在路径 res/animator 的文件夹里创建动画效果.xml文件


    此处设置为res/animator/set_animation.xml


    步骤2:设置动画参数

set_animation.xml
// ObjectAnimator 采用<animator>  标签

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="1" // initial value
android:valueTo="0" // end value
android:valueType="floatType" // change value type: floatType & intType
android:propertyName="alpha" // property name of object change

/>

在Java代码中启动动画
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.view_animation);  

// load XML animation

animator.setTarget(view);
// set animation object

animator.start();
// start animation

1.3 Use cases

此处先展示四种基本变换:平移、旋转、缩放 & 透明度
a. 透明度
mButton = (Button) findViewById(R.id.Button);
    // 创建动画作用对象:此处以Button为例

    ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f, 1f);
    // 表示的是:
    // 动画作用对象是mButton
    // 动画作用的对象的属性是透明度alpha
    // 动画效果是:常规 - 全透明 - 常规
    animator.setDuration(5000);
    animator.start();

insert image description here

b. 旋转
mButton = (Button) findViewById(R.id.Button);
    // 创建动画作用对象:此处以Button为例

ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, “rotation”, 0f, 360f);

    // 表示的是:
    // 动画作用对象是mButton
    // 动画作用的对象的属性是旋转alpha
    // 动画效果是:0 - 360
    animator.setDuration(5000);
    animator.start();

insert image description here

c. 平移
mButton = (Button) findViewById(R.id.Button);
    // 创建动画作用对象:此处以Button为例

float curTranslationX = mButton.getTranslationX();
// Get the position of the current button
ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, “translationX”, curTranslationX, 300, curTranslationX);
insert image description here

    // 表示的是:
    // 动画作用对象是mButton
    // 动画作用的对象的属性是X轴平移(在Y轴上平移同理,采用属性"translationY"
    // 动画效果是:从当前位置平移到 x=1500 再平移到初始位置
    animator.setDuration(5000);
    animator.start();



d. 缩放
mButton = (Button) findViewById(R.id.Button);
    // 创建动画作用对象:此处以Button为例

insert image description here

ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, “scaleX”, 1f, 3f, 1f);
// Indicates:
// The animation object is mButton
// The attribute of the animation object is the X-axis zoom
// The animation effect is: zoom in to 3 times, and then shrink to the initial size
animator.setDuration(5000);
animator.start();

2. Realize animation effects through custom object properties

    在上面的讲解,我们使用了属性动画最基本的四种动画效果:透明度、平移、旋转 & 缩放

2.1 Specific use

对于属性动画,其拓展性在于:不局限于系统限定的动画,可以自定义动画,即自定义对象的属性,并通过操作自定义的属性从而实现动画。
那么,该如何自定义属性呢?本质上,就是:

    为对象设置需要操作属性的set() & get()方法
    通过实现TypeEvaluator类从而定义属性变化的逻辑


    类似于ValueAnimator的过程

2.2 Examples

下面,我将用一个实例来说明如何通过自定义属性实现动画效果

    
        实现的动画效果:一个圆的颜色渐变 

insert image description here

        自定义属性的逻辑如下:(需要自定义属性为圆的背景颜色)
    


步骤1:设置对象类属性的set() & get()方法
设置对象类属性的set() & get()有两种方法:

    
        通过继承原始类,直接给类加上该属性的 get()& set(),从而实现给对象加上该属性的 get()& set()
    
    
        通过包装原始动画对象,间接给对象加上该属性的 get()& set()。即 用一个类来包装原始对象
    

此处主要使用第一种方式进行展示。

    关于第二种方式的使用,会在下一节进行详细介绍。

MyView2.java
public class MyView2 extends View {
    
    
// 设置需要用到的变量
public static final float RADIUS = 100f;// 圆的半径 = 100
private Paint mPaint;// 绘图画笔

private String color;
// 设置背景颜色属性

// 设置背景颜色的get() & set()方法
public String getColor() {
    
    
    return color;
}

public void setColor(String color) {
    
    
    this.color = color;
    mPaint.setColor(Color.parseColor(color));
    // 将画笔的颜色设置成方法参数传入的颜色
    invalidate();
    // 调用了invalidate()方法,即画笔颜色每次改变都会刷新视图,然后调用onDraw()方法重新绘制圆
    // 而因为每次调用onDraw()方法时画笔的颜色都会改变,所以圆的颜色也会改变
}
// 构造方法(初始化画笔)
   public MyView2(Context context, AttributeSet attrs) {
    
    
        super(context, attrs);
        // 初始化画笔
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

    // 复写onDraw()从而实现绘制逻辑
    // 绘制逻辑:先在初始点画圆,通过监听当前坐标值(currentPoint)的变化,每次变化都调用onDraw()重新绘制圆,从而实现圆的平移动画效果
    @Override
    protected void onDraw(Canvas canvas) {
    
    
        canvas.drawCircle(500, 500, RADIUS, mPaint);
    }
}
步骤2:在布局文件加入自定义View控件
activity_main.xml
    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="scut.carson_ho.valueanimator_ofobject.MainActivity">

    <scut.carson_ho.valueanimator_ofobject.MyView2
        android:id="@+id/MyView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         />
</RelativeLayout>
步骤3:根据需求实现TypeEvaluator接口
此处实现估值器的本质是:实现 颜色过渡的逻辑。
ColorEvaluator.java
 public class ColorEvaluator implements TypeEvaluator {
    
    
    // 实现TypeEvaluator接口

    private int mCurrentRed;

    private int mCurrentGreen ;

    private int mCurrentBlue ;

    // 复写evaluate()
    // 在evaluate()里写入对象动画过渡的逻辑:此处是写颜色过渡的逻辑
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
    
    

        // 获取到颜色的初始值和结束值
        String startColor = (String) startValue;
        String endColor = (String) endValue;

        // 通过字符串截取的方式将初始化颜色分为RGB三个部分,并将RGB的值转换成十进制数字
        // 那么每个颜色的取值范围就是0-255
        int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
        int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
        int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);

        int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
        int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
        int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);

        // 将初始化颜色的值定义为当前需要操作的颜色值
            mCurrentRed = startRed;
            mCurrentGreen = startGreen;
            mCurrentBlue = startBlue;


        // 计算初始颜色和结束颜色之间的差值
        // 该差值决定着颜色变化的快慢:初始颜色值和结束颜色值很相近,那么颜色变化就会比较缓慢;否则,变化则很快
        // 具体如何根据差值来决定颜色变化快慢的逻辑写在getCurrentColor()里.
        int redDiff = Math.abs(startRed - endRed);
        int greenDiff = Math.abs(startGreen - endGreen);
        int blueDiff = Math.abs(startBlue - endBlue);
        int colorDiff = redDiff + greenDiff + blueDiff;
        if (mCurrentRed != endRed) {
    
    
            mCurrentRed = getCurrentColor(startRed, endRed, colorDiff, 0,
                    fraction);
                    // getCurrentColor()决定如何根据差值来决定颜色变化的快慢 ->>关注1
        } else if (mCurrentGreen != endGreen) {
    
    
            mCurrentGreen = getCurrentColor(startGreen, endGreen, colorDiff,
                    redDiff, fraction);
        } else if (mCurrentBlue != endBlue) {
    
    
            mCurrentBlue = getCurrentColor(startBlue, endBlue, colorDiff,
                    redDiff + greenDiff, fraction);
        }
        // 将计算出的当前颜色的值组装返回
        String currentColor = "#" + getHexString(mCurrentRed)
                + getHexString(mCurrentGreen) + getHexString(mCurrentBlue);

        // 由于我们计算出的颜色是十进制数字,所以需要转换成十六进制字符串:调用getHexString()->>关注2
        // 最终将RGB颜色拼装起来,并作为最终的结果返回
        return currentColor;
    }
// 关注1:getCurrentColor()
// 具体是根据fraction值来计算当前的颜色。
    private int getCurrentColor(int startColor, int endColor, int colorDiff,
                                int offset, float fraction) {
    
    
        int currentColor;
        if (startColor > endColor) {
    
    
            currentColor = (int) (startColor - (fraction * colorDiff - offset));
            if (currentColor < endColor) {
    
    
                currentColor = endColor;
            }
        } else {
    
    
            currentColor = (int) (startColor + (fraction * colorDiff - offset));
            if (currentColor > endColor) {
    
    
                currentColor = endColor;
            }
        }
        return currentColor;
    }

    // 关注2:将10进制颜色值转换成16进制。
    private String getHexString(int value) {
    
    
        String hexString = Integer.toHexString(value);
        if (hexString.length() == 1) {
    
    
            hexString = "0" + hexString;
        }
        return hexString;
    }

}
步骤4:调用ObjectAnimator.ofObject()方法
MainActivity.java
 public class MainActivity extends AppCompatActivity {
    
    

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

        myView2 = (MyView2) findViewById(R.id.MyView2);
        ObjectAnimator anim = ObjectAnimator.ofObject(myView2, "color", new ColorEvaluator(),
                "#0000FF", "#FF0000");
        // 设置自定义View对象、背景颜色属性值 & 颜色估值器
        // 本质逻辑:
        // 步骤1:根据颜色估值器不断 改变 值 
        // 步骤2:调用set()设置背景颜色的属性值(实际上是通过画笔进行颜色设置)
        // 步骤3:调用invalidate()刷新视图,即调用onDraw()重新绘制,从而实现动画效果

        anim.setDuration(8000);
        anim.start();
    }
}
效果图

insert image description here

Name:
Xie Linchang
csdn:
https://blog.csdn.net/m0_57471214/article/details/128065331?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A% 22128065331%22%2C%22source%22%3A%22m0_57471214%22%7D

Guess you like

Origin blog.csdn.net/fjnu_se/article/details/128207896