概述
在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来实现各种插值器所完成的效果,所以在实际的开发中我们可以灵活运用~
网友评论