安卓修改动画效果--动画差值器TimeInterpolator

前一段时间让实现一个类似弹幕的效果,从右到左飘过去,时间八秒,嗯,很好做,一个动画就ok了

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <include layout="@layout/title_activity" />

    <Button
        android:id="@+id/bt"
        android:text="浮动轮播"
        android:layout_width="@dimen/dp100"
        android:layout_marginLeft="-100dp"
        android:layout_height="@dimen/dp40"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start"
        android:layout_marginTop="@dimen/dp100"
        android:id="@+id/btStart"/>

</LinearLayout>

文件代码:

val width = windowManager.defaultDisplay.width//获取屏幕的宽
val dp100 = R.dimen.dp100.toDimen()
btStart.setOnClickListener {
    //播放一个平移代码
    bt.startAnimator(AnimatorUtil.translationX, 8000, width.toFloat() + dp100, 0F)//这个工具类放在最后面
}

效果图:

需求出现了

现在改了需求,需要把弹幕的视图改成跟屏幕一样宽,然后动画时间还是8秒,但是需要在中间停留五秒

现在拆分需求

  1. 调整宽度,并且设置layout_marginLeft为屏幕宽
  2. 动画改变:从右往中间1.5秒播完,然后中间等5秒,然后从中间往左1.5秒播完

上手

调整宽度,布局代码,调整宽度

    <Button
        android:id="@+id/bt"
        android:text="浮动轮播"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp40"/>

然后把layout_marginLeft设置为负的屏幕的宽度

val layoutParams = LinearLayout.LayoutParams(width, R.dimen.dp40.toDimen().toInt())
layoutParams.leftMargin = -width
bt.layoutParams = layoutParams

然后直接改动画,把动画拆成三步,第一步从右走到中间,第二部停留五秒,第三部从中间走到左边

        btStart.setOnClickListener {
            bt.startAnimator(AnimatorUtil.translationX, 1500, width.toFloat() * 2, width.toFloat()) {
                if (it == AnimatorUtil.END) {
                    btStart.postDelayed({
                        //从右往左进到中间动画结束后,
                        //在中间停五秒
                        //然后再播从中间往左走到外面的动画
                        bt.startAnimator(AnimatorUtil.translationX, 1500, width.toFloat(), 0F)
                    }, 5000)
                }
            }
        }

效果图:

优化

虽然上面的动画确实做到了效果,但是安全性不高,并且嵌套也很深,能不能优化一下呢?

我们可以使用动画差值器来进行优化,并且可以把上面实现的两个动画缩减到一个动画,而且中间不用做定时操作,提升了安全性,也减少了嵌套

我们可以实现动画差值器的接口(TimeInterpolator)来实现上面的效果,接口源码:

public interface TimeInterpolator {
    float getInterpolation(float input);
}

该接口只有一个方法,输入的是动画执行的百分比,返回值也是动画执行的百分比,所以可以重写该方法来动态的调整进度实现变更的需求效果

代码如下:

        btStart.setOnClickListener {
            bt.startAnimator(AnimatorUtil.translationX, 8000, width.toFloat() * 2, 0F)
                    .setInterpolator {//添加一个动画差值器,这个是kt风格的代码,java也类似
                        return@setInterpolator when {
                            it <= 0.1875F -> //0.1875是1.5秒相对于8秒的比例值
                                //因为需要在0.1875(18.75%)走完0.5(50%),所以需要做一下数学计算
                                it / 0.1875F * 0.5F
                            it >= 0.8125F ->//0.8125‬是6.5秒相对于8秒的比例值
                                (it - 0.8125F) / 0.1875F * 0.5F + 0.5F
                            else -> 0.5F
                        }
                    }
        }

效果和上面一样,而且使用动画差值器基本可以不修改原有动画代码,并且可以实现很多的效果,当然,取决于自身的数学水平..

附上动画工具类的代码:

import android.animation.Animator
import android.animation.ObjectAnimator

/**
 * creator: lt  2019/8/9--18:46    [email protected]
 * effect : 属性动画工具类
 * warning:
 */

/**
 * 动画回调的状态
 */
typealias AnimatorState = Int

/**
 * 动画常用的属性和状态
 */
object AnimatorUtil {
    /**开始动画*/
    const val START: AnimatorState = 0
    /**动画结束*/
    const val END: AnimatorState = 1
    /**取消了动画*/
    const val CANCEL: AnimatorState = 2
    /**重复动画*/
    const val REPEAT: AnimatorState = 3

    /**透明动画*/
    const val alpha = "alpha"
    /**x轴旋转*/
    const val rotationX = "rotationX"
    /**y轴旋转*/
    const val rotationY = "rotationY"
    /**缩放x轴*/
    const val scaleX = "scaleX"
    /**缩放y轴*/
    const val scaleY = "scaleY"
    /**位移x轴*/
    const val translationX = "translationX"
    /**位移y轴*/
    const val translationY = "translationY"
}

/**
 * 开始一个属性动画
 */
fun Any.startAnimator(funName: String,
                      time: Long,
                      vararg floats: Float,
                      listener: ((AnimatorState) -> Unit)? = null): ObjectAnimator {
    val objectAnimator = ObjectAnimator.ofFloat(this, funName, *floats)
            .setDuration(time)
    if (listener != null) {
        objectAnimator.addListener(object : Animator.AnimatorListener {
            override fun onAnimationRepeat(animation: Animator?) {
                listener.invoke(AnimatorUtil.REPEAT)
            }

            override fun onAnimationEnd(animation: Animator?) {
                listener.invoke(AnimatorUtil.END)
            }

            override fun onAnimationCancel(animation: Animator?) {
                listener.invoke(AnimatorUtil.CANCEL)
            }

            override fun onAnimationStart(animation: Animator?) {
                listener.invoke(AnimatorUtil.START)
            }
        })
    }
    objectAnimator.start()
    return objectAnimator
}
发布了42 篇原创文章 · 获赞 192 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_33505109/article/details/102663504