更加自然的渐变——呼吸动画

10,785 阅读2分钟

本篇主要介绍通过定义属性动画来拟合呼吸函数的变化曲线,以实现更加自然的渐隐和渐显效果,当然也可以作用于其他属性的自然过渡。

这个函数是在这篇介绍交互的文章中发现的(让界面动画更自然)。




k=1/3,t=6, n={1,2,3,...}

(函数,及以上图片出自上文提到的链接)

此函数周期为6,貌似n是控制周期的,是不是呢,试一下。

这里令n=1进行MATLAB绘制函数图像,语句如下:

x=0:0.0000001:6;  
k=1/3;
t=6;
n=1;
y=(0.5*sin((pi/(k*t)).*((x-k*t/2)-(n-1)*t))+0.5).*(x>=(n-1)*t&x<(n-(1-k))*t)+((0.5*sin((pi/((1-k)*t)).*((x-(3-k)*t/2)-(n-1)*t))+0.5).^2).*(x>=(n-(1-k))*t&x<n*t);
grid on;
axis equal
axis([0 8 0 3])

得到图像如下:


由图像可见n=1时,即为函数第一个周期,由于这里要定义属性动画插值器,只需取函数的一个周期即可,所以就令n=1;定义插值器实现此函数如下:

package com.jaren.breatheanimationdemo;

import android.animation.TimeInterpolator;

/**
 * 定义拟合呼吸变化的插值器
 */

public class BraetheInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {

        float x = 6 * input;
        float k = 1.0f / 3;
        int t = 6;
        int n = 1;//控制函数周期,这里取此函数的第一个周期
        float PI = 3.1416f;
        float output = 0;

        if (x >= ((n - 1) * t) && x < ((n - (1 - k)) * t)) {
            output = (float) (0.5 * Math.sin((PI / (k * t)) * ((x - k * t / 2) - (n - 1) * t)) + 0.5);

        } else if (x >= (n - (1 - k)) * t && x < n * t) {
            output = (float) Math.pow((0.5 * Math.sin((PI / ((1 - k) * t)) * ((x - (3 - k) * t / 2) - (n - 1) * t)) + 0.5), 2);
        }
        return output;
    }
}
对插值器不太熟悉可以看一下这里。定义好插值器我们就可以按照属性动画的操作方式来实现我们需要的效果了。

首先看一下这个改变透明度实现渐隐、渐现的效果。

  /**
     * 开启透明度渐变呼吸动画
     */
    private void startAlphaBreathAnimation() {
        ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(tvShowBreathing, "alpha", 0f, 1f);
        alphaAnimator.setDuration(4000);
        alphaAnimator.setInterpolator(new BraetheInterpolator());//使用自定义的插值器
        alphaAnimator.setRepeatCount(ValueAnimator.INFINITE);
        alphaAnimator.start();
    }

效果:


用于缩放改变大小:

 /**
     * 开启缩放渐变呼吸动画
     */
    private void startScaleBreathAnimation() {
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(tvShowBreathing, "scaleX", 0.4f, 1f);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(tvShowBreathing, "scaleY", 0.4f, 1f);
        scaleX.setRepeatCount(ValueAnimator.INFINITE);
        scaleY.setRepeatCount(ValueAnimator.INFINITE);
        AnimatorSet animatorSet=new AnimatorSet();
        animatorSet.playTogether(scaleX,scaleY);
        animatorSet.setDuration(4000 );
        animatorSet.setInterpolator(new BraetheInterpolator());
        animatorSet.start();

    }

效果:


这里简单展示了一下两种使用效果,还有更多的场景适合使用,也可以给动画设置监听,用于自定义View等。

   animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                animation.getAnimatedValue();
                //...
            }
        });



如有缪误,欢迎指正!