美文网首页
[Android动画]属性动画-小球下落动画实现3

[Android动画]属性动画-小球下落动画实现3

作者: qiHuang112 | 来源:发表于2020-04-17 11:27 被阅读0次

前言

这篇文章是一个小球无限弹跳的动画效果,不说废话直接上效果吧

效果

效果图

代码

UI:R.layout.fragment_anim4

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_anim_0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_anim_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="reset"
        app:layout_constraintStart_toEndOf="@id/btn_anim_0"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_messages"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        app:layout_constraintTop_toBottomOf="@id/btn_anim_0" />

    <View
        android:id="@+id/view_anim"
        android:layout_width="10dp"
        android:layout_height="10dp"
        android:layout_marginLeft="20dp"
        android:background="#1F6FE8"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="2px"
        android:layout_marginTop="600px"
        android:background="#222222"
        app:layout_constraintTop_toBottomOf="@id/view_anim" />

</androidx.constraintlayout.widget.ConstraintLayout>

Fragment:AnimFragment4
如果你的demo是Activity,将layout绑定布局并吧initView方法放在onCreate中就好了

package com.qi.fragment.home

import android.animation.Animator
import android.animation.TypeEvaluator
import android.animation.ValueAnimator
import android.graphics.Color
import android.graphics.Outline
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.util.Log
import android.view.View
import android.view.ViewOutlineProvider
import android.view.animation.LinearInterpolator
import androidx.core.animation.doOnEnd
import androidx.core.animation.doOnStart
import com.qi.R
import com.qi.fragment.BaseFragment
import com.qi.util.Util
import com.qi.util.Util.location
import kotlinx.android.synthetic.main.fragment_anim4.*


/**
 * 估值器 - TypeEvaluator 模运动的小球
 * 第二阶段 - 通过组合动画实现小球的无限弹跳
 */
class AnimFragment4 : BaseFragment() {

    private var speedX = 250f
    private var speedY = -500f
    private var high = 600.0

    private var curAnim: Animator? = null

    companion object {
        const val a = 1000
        const val decay = 0.8
    }

    override fun getLayoutId() = R.layout.fragment_anim4

    override fun initViews() {

        // 裁剪为圆球形
        view_anim?.outlineProvider = object : ViewOutlineProvider() {
            override fun getOutline(view: View?, outline: Outline?) {
                outline?.setOval(0, 0, view_anim?.width ?: 0, view_anim?.height ?: 0);
            }
        }
        view_anim?.clipToOutline = true

        // 无限弹起下落过程
        btn_anim_0.setOnClickListener {
            getAnim().apply { curAnim = this }.start()
        }

        // reset
        btn_anim_1.setOnClickListener {
            curAnim?.cancel()
            curAnim?.cancel()
            curAnim?.removeAllListeners()
            speedX = 250f
            speedY = -500f
            high = 600.0
            view_anim.translationY = 0f
            view_anim.translationX = 0f
            view_anim.top = 955
            view_anim.bottom = 990
            view_anim.left = 70
            view_anim.right = 105
            showMessages()
        }
    }

    private fun getAnim(): ValueAnimator {
        val t = Util.getAns(0.5 * a, speedY.toDouble(), -high).toFloat()
        return ValueAnimator.ofObject(
            TypeEvaluator<Status> { fraction, _, _ ->
                val curT = fraction * t
                Status(speedX * curT, speedY * curT + 0.5f * a * curT * curT)
            },
            Status(),
            Status()
        ).apply {
            interpolator = LinearInterpolator() // 时间匀速变化
            duration = (t * 1000).toLong()
            addUpdateListener {
                (it.animatedValue as Status).apply {
                    view_anim.translationX = translationX
                    view_anim.translationY = translationY
                    showMessages()
                }
            }
            doOnStart {
                Log.d(TAG, view_anim.location)
            }
            doOnEnd {
                speedX *= decay.toFloat()
                speedY = -decay.toFloat() * (speedY + a * t)
                high = 0.0
            }
            doOnEnd {
                view_anim.top += (animatedValue as Status).translationY.toInt()
                view_anim.bottom += (animatedValue as Status).translationY.toInt()
                view_anim.left += (animatedValue as Status).translationX.toInt()
                view_anim.right += (animatedValue as Status).translationX.toInt()
                // 跳出屏幕或跳跃太小就停下来,防止无限循环
                if (view_anim.right < Util.width && (animatedValue as Status).translationX > 1) {
                    getAnim().apply { curAnim = this }.start()
                }
            }
        }
    }

    private fun showMessages() {
        val sb = SpannableStringBuilder()
            .append("left:", "#FF0000")
            .append(view_anim.left.toString()).append("\n")
            .append("right:", "#FF0000")
            .append(view_anim.right.toString()).append("\n")
            .append("top:", "#FF0000")
            .append(view_anim.top.toString()).append("\n")
            .append("bottom:", "#FF0000")
            .append(view_anim.bottom.toString()).append("\n")
            .append("TranslationX:", "#FF0000")
            .append(view_anim.translationX.toString()).append("\n")
            .append("TranslationY:", "#FF0000")
            .append(view_anim.translationY.toString()).append("\n")
            .append("SpeedX:", "#FF0000")
            .append(speedX.toString()).append("\n")
            .append("speedY:", "#FF0000")
            .append(speedY.toString()).append("\n")
        tv_messages.text = sb
    }

    data class Status(
        val translationX: Float = 0f, // x方向位移
        val translationY: Float = 0f, // y方向位移
        val rotation: Float = 0f, // 旋转角度:单位 °
        val alpha: Float = 1f, // 透明度
        val scaleX: Float = 1f, // 横向缩放
        val scaleY: Float = 1f // 纵向缩放
    )

    private fun SpannableStringBuilder.append(
        text: CharSequence,
        color: String
    ): SpannableStringBuilder {
        this.append(text)
        this.setSpan(
            ForegroundColorSpan(Color.parseColor(color)),
            this.length - text.length,
            this.length,
            0
        )
        return this
    }
}

Util.kt
如果你没有AppContext,自己写个方法获取applicationContext也是一样的,这里就不展示了

package com.qi.util

import android.content.Context
import android.view.View
import android.view.WindowManager
import com.qi.application.AppContext
import kotlin.math.pow

object Util {
    // 一元二次方程求解
    fun getAns(a: Double, b: Double, c: Double): Double {
        val delta = b * b - 4 * a * c
        return (-b + delta.pow(0.5)) / (2 * a)
    }

    val View.location
        get() = "top:$top, bottom:$bottom, left:$left, right:$right,translationX:$translationX, translationY:$translationY"

    val windowManager by lazy {
        AppContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    }
    val width by lazy {
        windowManager.defaultDisplay.width
    }
    val height by lazy {
        windowManager.defaultDisplay.height
    }
}

总结

感觉这个估值器还是有一定的缺点的,对于这些带衰减的动画效果,没有安置一个时间来控制,所以我写起来自己实现了时间,就显得很复杂了。但好歹还是有些收获,虽然以后可能用不太到- -

相关文章

网友评论

      本文标题:[Android动画]属性动画-小球下落动画实现3

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