美文网首页
Android自定义View(9) 《动画 插值器简介》

Android自定义View(9) 《动画 插值器简介》

作者: 非典型程序猿 | 来源:发表于2021-09-07 20:20 被阅读0次

概述

在Android中,我们经常会需要去绘制一些自己需要的控件,所以继承自View的自定义View就产生了。这篇文章主要介绍动画中的一些常用的插值器。关于插值器的使用这里就不再叙述了,有需要可以查看Android自定义View(5) 《自定义View,动画篇 视图动画》

Android自带插值器

1.AccelerateDecelerateInterpolator

加速减速插值器,刚开始和结束的时候速度会比较慢,中间会加速

2.AccelerateInterpolator

加速插值器,速度越来越快

3.DecelerateInterpolator

减速插值器动画开始的时候速度加速到最大值,接着越来越慢

4.LinearInterpolator

线性插值器,速率保持恒定

5.BounceInterpolator

弹性插值器,模拟了控件来回弹跳的样子‘

6.AnticipateInterpolator

初始偏移插值器,会在动画开始的时候先向前偏移然后再开始动画

7.OvershootInterpolator

结束偏移插值器,表示在结束时沿动画方向继续运动一段距离再结束动画

8.AnticipateOvershootInterpolator

开始和结束均偏移,是AnticipateInterpolator和OvershootInterpolator的合体。

9.CycleInterpolator

循环插值器,其构造函数

// cycles 循环次数
public CycleInterpolator(float cycles) {
        mCycles = cycles;
}

自定义插值器

其实系统的插值器使用都是比较简单的,那么我们如何来自定义一个属于自己的插值器呢?首先我们来看一下LinearInterpolator的源码

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.animation;

import android.content.Context;
import android.util.AttributeSet;

import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;

/**
 * An interpolator where the rate of change is constant
 */
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}

在这里我们要注意有这个方法

public float getInterpolation(float input) {
        return input;
}

这就是我们自定义插值器的关键了,我们需要实现Interpolator接口,并复写上述方法。该方法的input就是动画的执行进度,范围是0~1,根据动画的执行时间匀速输出,我们通过这个值来计算出动画实际的动画值,这个概念看过Android自定义View(6) 《自定义View,动画篇 属性动画 ValueAnimator》就可以理解了。线性插值器在这个方法中输出了input,也就是未做任何处理直接输出了,所以动画也就按0~1的进度匀速执行了。
接下来我们开始定义一个属于自己的简单的插值器,我们来直接实现动画的倒序播放

package com.tx.camera.view
import android.view.animation.Interpolator

/**
 * create by xu.tian
 *
 * @date 2021/9/5
 */
class MyInterpolator : Interpolator {

    override fun getInterpolation(input: Float): Float {
        return 1-input
    }
}

内容很简单,就是将原本0至1的输出结果,变为1至0,也就是倒序播放
接下来我们用之前的缩放例子来测试一下我们的插值器

   private void startScaleByCode(){
        /**
         * 主要使用了ScaleAnimation的构造方法,各个参数名字就不再解释了,跟上面xml文件中的一致
         * ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY)
         */
        ScaleAnimation animation = new ScaleAnimation(1f,0.5f,1f,0.5f,(binding.image.getWidth()/2),(binding.image.getHeight()/2));
        // 动画时间
        animation.setDuration(1000);
        // 动画结束时是否保持动画结束状态
        animation.setFillAfter(false);
        // 动画结束时是否保持动画开始时状态
        animation.setFillBefore(true);
        // 代码实现插值器
        animation.setInterpolator(new MyInterpolator());
        // 延迟执行动画
        animation.setStartOffset(0);
        // 开始动画
        binding.image.startAnimation(animation);
    }

运行结果

my_interpolator.gif

这里我们可以看到我们原本设置的是从1缩放到0.5,实际的运行结果却是从0.5开始放大到1,所以使用了我们的插值器后成功实现了倒放,自定义的插值器成功了~

Animator特有的Evaluator

视图动画仅支持插值器的使用,但是这里我们再介绍一个Animator特有的Evaluator的用法,刚刚我们说了,自定义插值器其实就是将动画的进度在指定的时长内分成了0到1,用来表示动画执行的进度。在介绍Evaluator之前呢,我们再来看之前我们使用的ValueAnimator。

// 开始执行动画
    fun startAnim() {
        var valueAnimator = ValueAnimator.ofFloat(0f, 500f)
        valueAnimator.duration = duration
        valueAnimator.interpolator = LinearInterpolator()
        valueAnimator.addUpdateListener { animation ->
            currentValue = animation?.animatedValue as Float
        valueAnimator.start()
    }

我们通过addUpdateListener来监听当前的动画值,而这个动画值与我们所设定的范围和动画的进度是有直接关系的,那么如何将我们的动画进度与具体的动画值联系到一起呢,这个时候就需要用到我们的Evaluator了。比如我们此时初始化了一个0f到500f的动画,那么我们可以自定义在0到1的动画进度内如何去返回具体的动画的值。

自定义Evaluator使用

package com.tx.camera.view

import android.animation.TypeEvaluator

/**
 * create by xu.tian
 * @date 2021/9/5
 */
class MyEvaluator : TypeEvaluator<Int> {
    override fun evaluate(fraction: Float, startValue: Int, endValue: Int): Int {
        return (startValue+(fraction*(endValue- startValue!!))).toInt()
    }
}

这里呢我们实现了最基础的线性变化的Evaluator,fraction也就是动画的进度,范围0到1,我们就在动画开始值的进度上加上跟随时间线性变化的值,所以我们在这里实现了和线性插值器一样的动画,注意TypeEvaluator的泛型要与你动画中的设定的值动画的类型一致,否则会出错。

自定义Evaluator使用

 private void startValueAnim(){
        ValueAnimator animator ;
        if (binding.image.getLeft()>0){
            animator = ValueAnimator.ofInt(500,0);
        }else {
            animator = ValueAnimator.ofInt(0,500);
        }
        animator.setDuration(500);
        animator.setEvaluator(new MyEvaluator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currentValue = (int) animation.getAnimatedValue();
        binding.image.layout(currentValue,currentValue,currentValue+binding.image.getWidth(),currentValue+binding.image.getHeight());
            }
        });
        animator.start();
    }

运行效果

Evaluator.gif

下面我们再修改一下,把它变成瞬移,在动画执行到一半时直接放在动画结束的位置

package com.tx.camera.view

import android.animation.TypeEvaluator

/**
 * create by xu.tian
 * @date 2021/9/5
 */
class MyEvaluator : TypeEvaluator<Int> {
    override fun evaluate(fraction: Float, startValue: Int, endValue: Int): Int {
        if (fraction>0.5){
            return endValue
        }
        return startValue
    }
}

当进度超过0.5时我们直接返回结束的动画值,否则就放在初始值不动

运行结果

ezgif.com-gif-maker.gif

所以再次验证了我们的Evaluator生效啦

总结

动画值的控制一方面可以利用插值器,另一方面Animator也可以使用Evaluator来实现各种插值器所完成的效果,所以在实际的开发中我们可以灵活运用~

相关文章

网友评论

      本文标题:Android自定义View(9) 《动画 插值器简介》

      本文链接:https://www.haomeiwen.com/subject/vbojwltx.html