[Android 动画] 实现类似弹簧的插值器SpringInterpolator

来源:互联网 发布:linux审计日志分析 编辑:程序博客网 时间:2024/06/09 23:44

一、前言

        在我们移动app的开发中,用户与输入框editText的交互应该是必不可少的。为了为用户提供更好的交互体验,我们这样规定:如果用户输入了不符合规则的内容,我们将调用一个抖动的动画,来提示用户这个输入不合规定。关于Android中动画的知识我就不在这里赘述了,文章最后会给大家介绍一些不错的相关文章。

二、将要实现的效果

    1.文字描述

    如果用户输入了不符合规则的文字,我们调用抖动动画来实现一个提示的功能。

    2.gif图展示

   

三、实现思路

    1.了解插值器Interpolator

    Android中动画包括View动画,Drawable(帧)动画,Animator属性动画等。不熟悉的朋友们可以先去了解相关的知识,如果你对自己悟性有很大的把握,那么可以继续看下去。

    首先用一种匀速向右移动的动画来举例。

    大家应该都知道匀速运动,在整个过程中速率不变,加速度为0,如果用坐标函数图象来表示位移x与时间t的关系的话,将会是下图的样子:

    下面我们引入一个官方的插值器来解释一下插值器是用来干什么的

    DecelerateInterpolator,decelerate中文意思是减速,官方给的解释是一种先加速后减速的插值器。在使用了这个插值器之后,我们用坐标函数图像再次表示一下x与t的关系,方便比较:

    从图像来看,x的变化速率由高到低,从数学知识中不难得出在x坐标上的速度先加快后减慢。那我们不妨假设,插值器的作用就是改变x与t的坐标图象,我们把纵坐标看作是偏移量translateX,横坐标看作动画周期t,虽然不知道具体是怎么实现的,但是从感觉上好像是对的,抱着这样的想法我们开始对源码进行解读。


    2.解读源码中的Interpolator

    依然用DecelerateInterpolator来做例子。在官方给的解释中我们知道了DecelerateInterpolator是先快后慢的插值器,我们查看源码中的getInterpolator方法,这个方法就是实现插值器功能的部分。源码如下:

public float getInterpolation(float input) {        float result;        if (mFactor == 1.0f) {            result = (float)(1.0f - (1.0f - input) * (1.0f - input));        } else {            result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));        }        return result;    }

    先不管mFactor!=1.0f的情况,我们根据x=(1.0f-(1.0f-input)*(1.0f-input))画出x随t变化的函数图像如下图

    得出来的图像完全符合我们第一阶段的分析,我们再看看x=(1.0f-(1.0f-input)*(1.0f-input)),如果把input换成t就可以写作x=1-(1-t)*(1-t)这应该就是一条抛物线的图像了,并且当t=1的时候x=1。需要说明的一点是input表示当前动画执行的百分比,是float类型。比如动画执行了一半,input=0.5f。

    如果按照自己的想法,这种插值器还有没有另外的写法。答案是肯定的:

    从图像来看,x的变化速率由高到低,从数学知识中不难得出在x坐标上的速度先加快后减慢,想想我们学到过的数学知识,不妨用最简单的三角函数来模拟这一段函数图像。

    我们将振幅定为1;

    运动时间定为1;

    那么根据图像,三角函数周期应该是4;

    最终我们可以得出x=1*sin(1/4*t*2*Pai)。感兴趣的朋友可以自定义一个插值器,按照这样的公式去做返回值,相信你可以做出来同样的效果。

    3.分析运动过程,实现自己的SpringInterpolator(弹簧插值器)

    此时我们再回过头来看我们的需求,我们需要的就是让x与t的函数图像变成下面这样:

    倒吸一口气!这不就是个正弦函数嘛!谁说不是呢,不过一定要把他的周期振幅等正确的计算出来。在源码部分已经解释过了input是0~1.0f的float数,那这个正弦函数的周期应该是1,振幅x,其实就是我们自己设置的偏移量。最终给出来我计算出来的公式:x=sin(input*2*Pai),并根据该公式自定义自己的弹簧插值器SpringInterpolator。

四、关键代码解析

    最关键的当然是SpringInterpolator.class的代码咯!

import android.content.Context;import android.util.AttributeSet;import android.view.animation.Interpolator;/** * 模拟弹簧左右弹动的插值器 * @author Mr-Zhang * */public class SpringInterpolator implements Interpolator{public SpringInterpolator() {}public SpringInterpolator(Context context,AttributeSet attrs){}@Overridepublic float getInterpolation(float input) {return (float) Math.sin(input * 2 * Math.PI);}}

    大家可以看到,核心代码就一行Math.sin(input*2*Math.PI)。接下来就看一下我们如何去使用它把。

五、使用方法

    再回顾一下我们想要实现的效果:用插值器实现一个使控件像弹簧一样抖动的动画。下面是使用方法:

import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.animation.Animation;import android.view.animation.TranslateAnimation;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import com.mr_zhang.diyviewgroup.R;import com.mr_zhang.diyviewgroup.diyinterpolator.SpringInterpolator;/** * Created by mr-zhang on 2016/3/25. */public class ShowSpringAnimatorActivity extends Activity {    private TextView tvSpring;    private EditText etToX;    private EditText etDuration;    private Button btnReset;    private TranslateAnimation animation;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_show_spring_animator);        etToX = (EditText) findViewById(R.id.et_toX);        etDuration = (EditText) findViewById(R.id.et_duration);        btnReset = (Button) findViewById(R.id.btn_reset);        tvSpring = (TextView) findViewById(R.id.tv_spring);        tvSpring.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                tvSpring.startAnimation(animation);            }        });        btnReset.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                animation = new TranslateAnimation(0, Float.valueOf(etToX.getText().toString()), 0, 0);                animation.setDuration(Long.valueOf(etDuration.getText().toString()));                animation.setRepeatMode(Animation.RESTART);                animation.setRepeatCount(-1);                animation.setInterpolator(new SpringInterpolator());            }        });    }}

    setDuration()设置动画周期(1s结束动画);

    setRepeatMode()动画重复模式(Animation.RESTART重新开始动画,另一种是倒叙播放动画);

    setRepeatCount()设置重复次数;

    最关键的最后一句,setInterpolator设置插值器

    这就是插值器。

六、总结与分享

    这篇文章拖了很久才酝酿出来,也是由于生活中的原因,总觉得没时间去做。但是当我去做了这件事的时候,才发现,并不是没有时间,只是懒,懒得去动手,懒得在休息时间也要动脑,懒得运动,懒得。。。。。。然后肚子肥了,梦想没了,泪目了。。。索性我还没有忘记,总算在百忙之中抽出时间,完成了这篇文章。写第一篇文章的时候觉得,哇!好简单啊,我一周可以写一篇,然后很尴尬啊,我的一周竟然达到了将近60天,汗颜。索性,最终还是完成了,开心!。

    最后分享一篇相关的文章吧。http://blog.csdn.net/yanbober/article/details/46481171 这篇博文讲了关于基本的Android动画的一些知识,适合最基本的动画的学习。我也是从这篇博文中学习的基础的Android动画知识。希望大家也能从中有所收获。共勉。

0 0
原创粉丝点击