Android自定义View基础之Animation-属性动画篇

555 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

前面讲完了视图动画篇 Android自定义view基础之Animation(动画)-视图动画篇 - 掘金 (juejin.cn)

帧动画

对一系列的图片进行逐个反映,从而形成动画效果

逐帧动画是用Drawable的一个子类AnimationDrawable类来实现的

使用

  • 第一步

    在Drawable目录下新建Drawable Resource file,类型选择为animation-list

  • 第二步

    准备图片,网上搜逐帧动画就会有很多资源

  • 第三步

    编写代码xml

<?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/img_one" android:duration="200"/>
    <item android:drawable="@drawable/img_tow" android:duration="200"/>
    <item android:drawable="@drawable/img_three" android:duration="200"/>
</animation-list>

属性 oneshot代表是否只只播放一次,否则循环播放

  • 第四步

在activity中编写代码

ImageView imageView= findViewById(R.id.imageView);
imageView.setBackgroundResource(R.drawable.myframeanimation);//设置背景为帧动画
AnimationDrawable background = (AnimationDrawable)imageView.getBackground();//拿到设置的背景
background.start();//开始动画

之后重新运行你的程序就可以看到效果了

属性动画

属性动画与前面两种动画的区别是其属性值会真正发生改变

属性动画分三类

  • ViewPropertyAnimator
  • ObjectAnimatior
  • ValueAnimator

ViewPropertyAnimator

这个动画与其他两个动画不同的是它不能自定义属性,只能使用系统自带的属性(平移,放缩,透明度,旋转),相对来说它更像视图动画,只不过它的属性值是真正改变的。

使用

view.animate();方法就可以返回一个ViewProperty对象

image.png

如上图这是基本属性,同样Scale rotate 也有

by表示在原来的基础上变化多少

其余的表示移动到一个什么样的位置

  • 可以组合来使用一系列的动画
imageView.animate().alpha(1).scaleY(1).scaleX(1);
  • 配置方法

image.png

ObjectAnimation

  • 基本使用
ObjectAnimator animator = ObjectAnimator.ofFloat(
        imageView, "translationX", 0,600,500,600);
animator.setDuration(2000);
animator.start();

objectAnimator提供了一系列的of方法

image.png

第一个参数为你要操作的view,如上述代码为imagineView

第二个参数为要操作的属性,系统有内置的一些基础操作,当然我们也可以自定义属性

第三个参数为可变参数,也就是一个数组,你选用什么类型的函数就填什么类型的数据类型,比如 ofFloat 就填浮点型,ofObject 就填某一个类的对象

在填入的数组中第一号元素为初始态,最后一位元素为最终态,中间元素为中间过渡态

eg在上述代码中imageview会沿着x方向0 ->600->500->600

自定义属性

在上述我们所填入的translateX,其实,这个方法会在View内部拼接为该类属性的setter方法,并触发重绘 有没有什么启发呢?

我们在自定义view的时候是不是可以用到,例如下面代码,来制作一个圆形进度条

public class PathView extends View {

    public PathView(Context context) {
        super(context);
    }

    public PathView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public PathView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public PathView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    Paint paint=new Paint();

    public float getProgress() {
        return progress;
    }

    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();//每次数值改变触发重绘
    }

    private float progress;

    @Override
    protected void onDraw(Canvas canvas) {
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(20);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setAntiAlias(true);
        canvas.drawArc(rectF,135,progress*2.7f,false,paint);//绘制进度条
        //一个百分比代表 3.6度

        paint.setStrokeWidth(3);
        paint.setTextSize(50);
        int a=(int) progress;
        canvas.drawText((a)+"%",210,250,paint);//绘制百分比
    }
}

让后在activity中

ObjectAnimator animator=ObjectAnimator.ofFloat(pathView,"progress",0,100,60);
animator.setDuration(3000);
animator.start();

AB17E38DFA84B0AA6C22A743C6581EF0.gif

如上代码所示 定义一个progress 变量,改写其set方法,其实就是加入invalidate触发onDraw 方法来重绘,不断重绘就会触发动画

设置多个动画播放顺序

AnimatorSet

AnimatorSet animatorSet = new AnimatorSet();
// 两个动画依次执行
animatorSet.playSequentially(animator1, animator2);
animatorSet.start();
// 两个动画同时执行
animatorSet.playTogether(animator1, animator2);
animatorSet.start();
// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式来精确配置各个 Animator 之间的关系
animatorSet.play(animator1).with(animator2);
animatorSet.play(animator1).before(animator2);
animatorSet.play(animator1).after(animator2);
animatorSet.start();
    • after(Animator anim) :将现有动画插入到传入的动画之后执行
    • after(long delay) :将现有动画延迟指定毫秒后执行
    • before(Animator anim): 将现有动画插入到传入的动画之前执行
    • with(Animator anim) :将现有动画和传入的动画同时执行

ValueAnimator

valueAnimator:这个动画是针对属性的值进行动画的 ,不会对UI造成改变,不能直接实现动画效果。需要通过对动画的监听去做一些操作,在监听中将这个值设置给对应的属性,对应的属性才会改变。

ValueAnimator sunAnimator = ValueAnimator.ofFloat(startAngle, currentAngle);
sunAnimator.setDuration(duration);
sunAnimator.addUpdateListener(animation -> {
    mCurrentAngle = (float) animation.getAnimatedValue();//修改属性值
    invalidate();//触发onDRaw 方法来重绘
});
sunAnimator.start();//开始动画

相对来说ValueAnimator更像是一个数值改变器,我们获取实时的数值对我们的属性赋值来生成动画