欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android属性动画学习一

程序员文章站 2024-03-21 11:26:58
...

原文链接
对于属性动画的使用,主要有:
两个使用方法类:ValueAnimator 类 & ObjectAnimator 类
两个辅助使用类:插值器 & 估值器

ValueAnimator类的学习

ValueAnimator类中有3个重要方法:

  • ValueAnimator.ofInt(int... values)
  • ValueAnimator.ofFloat(float... values)
  • ValueAnimator.ofObject(TypeEvaluator evaluator, Object... values)
    逐一介绍这三个方法

1.ValueAnimator.ofInt(int… values)

作用

将初始值 以整型数值的形式 过渡到结束值

即估值器是整型估值器 - IntEvaluator

实例使用
public class MainActivity extends AppCompatActivity {
    Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=findViewById(R.id.btn_anim);
        init();
    }
    private void init() {
        //设置属性数值的初始值 & 结束值
        ValueAnimator valueAnimator=ValueAnimator.ofInt(button.getLayoutParams().width,500);
        // 步骤2:设置动画的播放各种属性
        // 设置动画运行时长
        valueAnimator.setDuration(2000);
        //设置重复次数
        //ValueAnimator.INFINITE:无限次播放
        valueAnimator.setRepeatCount(5);  //播放动画6次(5+1)
//        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        //设置模式
        // ValueAnimator.RESTART(默认):正序重放
        // ValueAnimator.REVERSE:倒序回放
        valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
        // 步骤3:将属性数值手动赋值给对象的属性:此处是将值赋给按钮的宽度
        // 设置更新监听器:即数值每次变化更新都会调用该方法
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                // 获得每次变化后的属性值
                int currentWidth= (int) valueAnimator.getAnimatedValue();
                // 输出每次变化后的属性值进行查看
                System.out.println(currentWidth);
                // 每次值变化时,将值手动赋值给对象的属性
                button.getLayoutParams().width=currentWidth;
                // 步骤4:刷新视图,即重新绘制,从而实现动画效果
                button.requestLayout();
            }
        });
        valueAnimator.start();
    }
}

效果图:
Android属性动画学习一
注意看你的输出,可以看到动画的宽度是在实时变化的
Android属性动画学习一

2.ValueAnimator.ofFloat(float… values)

同ValueAnimator.ofInt(int… values),注意是浮点型就行。

3.ValueAnimator.ofObject(TypeEvaluator evaluator, Object… values)

作用

将初始值 以对象的形式 过渡到结束值

即通过操作 对象 实现动画效果

估值器(TypeEvaluator)

估值器的作用:设置动画如何从初始值过渡到结束值的逻辑

插值器(Interpolator)决定值的变化模式(匀速、加速blabla)
估值器(TypeEvaluator)决定值的具体变化数值

ValueAnimator.ofInt和ValueAnimator.ofFloat方法是内置了估值器的,ofObject需要自定义估值器。先看看ValueAnimator.ofFloat的估值器FloatEvaluator 的代码实现:

public class FloatEvaluator implements TypeEvaluator {  
// FloatEvaluator实现了TypeEvaluator接口

// 重写evaluate()
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
        float startFloat = ((Number) startValue).floatValue();  
        
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);  
        // 初始值 过渡 到结束值 的算法是:
        // 1. 用结束值减去初始值,算出它们之间的差值
        // 2. 用上述差值乘以fraction系数
        // 3. 再加上初始值,就得到当前动画的值
    }  
}  

从上面可知,自定义估值器的逻辑如下:

// 实现TypeEvaluator接口
public class ObjectEvaluator implements TypeEvaluator{  
// 复写evaluate()
// 在evaluate()里写入对象动画过渡的逻辑
    @Override  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        // 参数说明
        // fraction:表示动画完成度(根据它来计算当前动画的值)
        // startValue、endValue:动画的初始值和结束值
        // 写入对象动画过渡的逻辑
        return value;  
        // 返回对象动画过渡的逻辑计算后的值
    }  
  
实例使用
  • 效果
    Android属性动画学习一
    完成这个小案例需要四个类
  • MainActivity
  • MyView
  • Point
  • PointEvaluator

Point.java

  • 因为ValueAnimator.ofObject()是面向对象操作的,所以需要自定义对象类。
  • 本例需要操作的对象是 圆的点坐标
public class Point {
    // 设置两个变量用于记录坐标的位置
    float x;
    float y;
    public Point(float x,float y){
        this.x=x;
        this.y=y;
    }
    // get方法用于获取坐标
    public float getX() {
        return x;
    }
    public float getY() {
        return y;
    }
}

PointEvaluator.java

  • 实现TypeEvaluator接口的目的是自定义如何 从初始点坐标 过渡 到结束点坐标
  • 本例实现的是一个从左上角到右下角的坐标过渡逻辑
  • 在其他案例中根据需求自定义TypeEvaluator的实现
public class PointEvaluator implements TypeEvaluator {
   // 复写evaluate()
    // 在evaluate()里写入对象动画过渡的逻辑
    @Override
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        // 将动画初始值startValue 和 动画结束值endValue 强制类型转换成Point对象
        Point start= (Point) startValue;
        Point end= (Point) endValue;
        // 根据fraction来计算当前动画的x和y的值
        float x=start.getX()+fraction*(end.getX()-start.getX());
        float y=start.getY()+fraction*(end.getY()-start.getY());
         // 将计算后的坐标封装到一个新的Point对象中并返回
        Point point=new Point(x,y);
        return point;
    }
}

MyView.java

  • 将属性动画作用到自定义View当中
public class MyView extends View {
    // 设置需要用到的变量
    public static final float RADIUS = 70f;// 圆的半径 = 70
    private Point currentPoint;// 当前点坐标
    private Paint mPaint;// 绘图画笔


    public MyView(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) {
        super.onDraw(canvas);
        if (currentPoint==null){
            currentPoint=new Point(RADIUS,RADIUS);
            float x=currentPoint.getX();
            float y=currentPoint.getY();
            canvas.drawCircle(x,y,RADIUS,mPaint);
            // (重点关注)将属性动画作用到View中
            // 步骤1:创建初始动画时的对象点  & 结束动画时的对象点
            Point start=new Point(RADIUS,RADIUS);
            Point end=new Point(700,1000);
            // 步骤2:创建动画对象 & 设置初始值 和 结束值
            ValueAnimator animator=ValueAnimator.ofObject(new PointEvaluator(),start,end);
            // 步骤3:设置动画参数
            // 设置动画时长
            animator.setDuration(5000);
            //设置重复次数
            animator.setRepeatCount(5);  //播放动画6次(5+1)
            //ValueAnimator.INFINITE:无限次播放
            //设置模式
            // ValueAnimator.RESTART(默认):正序重放
            // ValueAnimator.REVERSE:倒序回放
            animator.setRepeatMode(ValueAnimator.REVERSE);
            // 通过更新监听器,将改变的对象手动赋值给当前对象
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    //将每次变化后的坐标值(估值器PointEvaluator中evaluate()返回的Piont对象值)到当前坐标值对象(currentPoint)
                    // 从而更新当前坐标值(currentPoint)
                    currentPoint= (Point) valueAnimator.getAnimatedValue();
                    // 步骤4:每次赋值后就重新绘制,从而实现动画效果
                    invalidate();
                    // 调用invalidate()后,就会刷新View,即才能看到重新绘制的界面,即onDraw()会被重新调用一次
                    // 所以坐标值每改变一次,就会调用onDraw()一次
                }
            });
            animator.start();
        }else {
            // 如果坐标值不为0,则画圆
            // 所以坐标值每改变一次,就会调用onDraw()一次,就会画一次圆,从而实现动画效果
            float x = currentPoint.getX();
            float y = currentPoint.getY();
            canvas.drawCircle(x, y, RADIUS, mPaint);
        }
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
   <cn.hichips.propertyanim.MyView 
           android:layout_width="match_parent" 
           android:layout_height="match_parent"/>
</LinearLayout>
相关标签: 转载笔记