讓View具有減速效果的動畫——FlingAnimation

xingfeng_coder發表於2019-03-22

Google除了提供了屬性動畫之外,還提供了一種基於物理的動畫,叫做DynamicAnimation,與物理世界更貼近,關於這塊可以參考https://www.jianshu.com/p/46b1cdc253e9。

目前主要有兩種DynamicAnimation,分別是:

本文主要介紹Fling Animation。話不多說,先看下官方demo示例:

Fling Animation官方demo

在鬆手後,會繼續有動畫的效果,逐漸減慢直至停止,是不是和現實生活中很類似?因為有摩擦力,所以會不斷減少,這時高中老師教給我們的牛頓力學可以發揮用場了。

再來看下本文最終的demo示例:

本文demo示例

拖動ImageView,鬆手的一瞬間,如果垂直方向的加速度大於水平方向的,那麼垂直方向進行動畫;反之水平方向運動,運動範圍限制在螢幕中。

FlingAnimation的使用

FlingAnimation的使用主要分為兩步驟:

  1. 新增支援庫
dependencies {
      implementation 'com.android.support:support-dynamic-animation:28.0.0'
  }
複製程式碼
  1. 建立一個FlingAnimation
val fling = FlingAnimation(view, DynamicAnimation.SCROLL_X)
複製程式碼

FlingAnimation的建立需要指定View以及動畫的屬性,接下來就是設定一些屬性,

  • setStartVelocity(float):設定起始加速度,單位是改變的屬性每秒,預設是0。如果需要使用dp轉pixel,可以使用下段程式碼:
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond,
       getResources().getDisplayMetrics());
複製程式碼
  • setMinValue(float):設定動畫的最小值。這個值是建立FlingAnimation中的屬性值的最小值,也就是說屬性值不過小於該值。
  • setMaxValue(float):與上面類似,只不過是最大值,min<=屬性值<=max。
  • setFriction(float):設定摩擦力,學過力學的都知道,沒有摩擦力,那麼將一直運動下去;而摩擦力越大,那麼將會越快停止,預設值是1。
  • setMinimumVisibleChange(float):當建立一個單位不是pixel的自定義屬性時,需要設定該值;DynamicAnimation.ViewProperty裡面的屬性是不需要設定該值的。

Demo示例程式碼

學完了理論知識,就看一下程式碼了,佈局很簡單,就一個ImageView,將touch事件交給了GestureDetector,然後在onFling()方法中實現FlingAnimation動畫;有一點需要注意的是,FlingAnimation改變的是transitionX和transitionY屬性,為了限制在螢幕內動畫,因此計算了x和y方向的最大值,具體程式碼如下:

class FlingAnimationActivity : AppCompatActivity() {

    lateinit var gestureDetector: GestureDetector
    var maxTransitionX: Int? = null
    var maxTransitionY: Int? = null
    
    private val gestureListener = object : GestureDetector.SimpleOnGestureListener() {
        override fun onDown(e: MotionEvent?): Boolean {
            return true
        }

        override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
            if (Math.abs(velocityX) > Math.abs(velocityY)) {
                FlingAnimation(ivImg, DynamicAnimation.TRANSLATION_X).apply {
                    setStartVelocity(velocityX)
                    setMinValue(0f)
                    setMaxValue(maxTransitionX!!.toFloat())
                    friction = 1.1f
                    start()
                }
            } else {
                FlingAnimation(ivImg, DynamicAnimation.TRANSLATION_Y).apply {
                    setStartVelocity(velocityY)
                    setMinValue(0f)
                    setMaxValue(maxTransitionY!!.toFloat())
                    friction = 1.1f
                    start()
                }
            }
            return true
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_fling)

        mainLayout.viewTreeObserver.addOnGlobalLayoutListener {
            maxTransitionX = mainLayout.width - ivImg.width
            maxTransitionY = mainLayout.height - ivImg.height
        }

        gestureDetector = GestureDetector(this, gestureListener)

        ivImg.setOnTouchListener { v, event ->
            gestureDetector!!.onTouchEvent(event)
        }
    }
}
複製程式碼

參考文章

關注我的技術公眾號,不定期會有技術文章推送,不敢說優質,但至少是我自己的學習心得。微信掃一掃下方二維碼即可關注:

二維碼

相關文章