炫酷!從未見過如此Q彈的Switcher

前言

最近逛Dribbble的時候,看到了一個很是酷的Switcher動畫,特別喜歡,本想着試着用代碼在Android平臺來實現一下,沒想到已經有實現的版本,而且做者還寫了文章分享,思路清晰,各個實現關鍵點都講的特別清楚,所以就譯誠中文,分享你們,正如做者最後所說,你們必定要運行試試,效果很是贊!android

原做者: Alexander Kolpakov
譯者: 依然範特稀西
地址: http://suo.im/60UJjT

正文開始

最近,我寫了一篇關於實現Dribbble上的一個漂亮設計的文章。獲得了不少積極的反饋,對我來講,這給了我很大的動力。我很是高興能得到這些反饋,同時我也很樂意分享個人經驗。git

在本文中,咱們將嘗試逐步實現由Oleg Frolov建立的另外一個精美的動畫。這與上一篇文章中的複雜動畫UI無關,它是一個自定義小控件。可是它有着很是精美漂亮的動畫設計,以下所示:github

swicher.gif

乍一看,實現這樣的切換彷佛並不簡單,但我認爲那是由於動畫很是漂亮。如 你所見,建立相同的動畫並不難。讓咱們一步一步地來實現它。spring

第一步,咱們須要自定義View,而且實現它的3個構造方法:canvas

class Switcher @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet ? = null,
        defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
      
    init {
        attrs?.let { retrieveAttributes(attrs, defStyleAttr) }
    }
  
    private fun retrieveAttributes(attrs: AttributeSet, defStyleAttr: Int) {
        // retrieve cutom attributes
    }
  
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        // setup switcher width and height
    }
  
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        // setup helper sizes every time switcher size changed (radius, icon width...)
    }
      
    override fun onDraw(canvas: Canvas ?) {
        // just draw
    }
}

接下來開始繪製

在默認(選中)狀態下,咱們的開關由2個圓角矩形(綠色和白色)組成微信

繪製它們很是簡單,咱們只須要計算白色矩形的位置並將偏移量iconTranslateX傳遞給Android KTX Canvas.withTranslation擴展便可:app

override fun onDraw(canvas: Canvas ?) {
  // draw switcher (green rect)
  canvas?.drawRoundRect(switcherRect, switcherCornerRadius, switcherCornerRadius, switcherPaint)

  // draw icon (white rect)
  canvas?.withTranslation(x = iconTranslateX) {
      drawRoundRect(iconRect, switcherCornerRadius, switcherCornerRadius, iconPaint)
  }
}

開始分解動畫

動畫部分,咱們使用ValueAnimator來實現,使用它的ofFloat(float... values)方法,咱們須要三個動畫:ide

  • 一、switcherAnimator : 切換器圖標動畫,從白色矩形到圓形,反之亦然
  • 二、translateAnimator: 爲切換器圖標從左到右的過渡設置動畫,反之亦然;
  • 三、colorAnimator : 將顏色從綠色(選中)更改成紅色,反之亦然。

讓咱們先看一下switcherAnimator 動畫,設置0爲動畫的開始值,1爲動畫的結束值。post

// ...
var amplitude = BOUNCE_ANIM_AMPLITUDE_IN
var frequency = BOUNCE_ANIM_FREQUENCY_IN
var newProgress = 1f

if (!checked) {
    amplitude = BOUNCE_ANIM_AMPLITUDE_OUT
    frequency = BOUNCE_ANIM_FREQUENCY_OUT
    newProgress = 0f
}

val switcherAnimator = ValueAnimator.ofFloat(iconProgress, newProgress).apply {
    addUpdateListener {
        iconProgress = it.animatedValue as Float
    }
    interpolator = BounceInterpolator(amplitude, frequency)
    duration = SWITCHER_ANIMATION_DURATION
}
// ...

咱們可使用 Evgenii Neumerzhitckii 寫的BounceInterpolator 來實現反彈效果,這很是適合咱們的動畫場景,不瞭解的能夠看一下這片文章:https://evgenii.com/blog/spring-button-animation-on-android/,它解釋了BounceInterpolator是如何工做的。動畫

在Android KTX addUpdateListener擴展中,咱們更新了progress的值,而後觸發invalidate 方法,最後從新繪製了視圖。

private var iconProgress = 0f
  set(value) {
      if (field != value) {
          field = value
        
          val iconOffset = lerp(0f, iconRadius - iconCollapsedWidth / 2, value)
          iconRect.left = width - switcherCornerRadius - iconCollapsedWidth / 2 - iconOffset
          iconRect.right = width - switcherCornerRadius + iconCollapsedWidth / 2 + iconOffset

          postInvalidateOnAnimation()
      }
  }

lerp方法相似一個線性插值器,它用於計算iconOffset ,反過來,它也用於計算Swicher圖標的圓角矩形座標。此圖標的矩形從一個圓角矩形變爲一個圓形(圓角半徑較大的圓角矩形)。

咱們使用了 postInvalidateOnAnimation()代替 postIvalidate ,是由於咱們須要平滑的動畫,而且第一個方法有優點,詳情請看: https://stackoverflow.com/questions/29219372/postinvalidateonanimation-vs-postinvalidate/42648958#42648958

translateAnimator的工做方式相同,可是會更新Swicher圖標的x位置。

如你所見,咱們的白色圓圈就像百吉餅。咱們有2種製做方法:

  • 裁剪一個較小的圓圈
  • 最簡單的圓圈,只需在頂部繪製另外一個小圓圈,而後用切換器顏色填充便可。

我選擇較簡單的一種。

這一切,沒什麼難的!咱們如今有一個漂亮的自定義小控件而且帶有精美的動畫!

至此,咱們一切均可以了

如今,咱們可使用任何類型的動畫來建立自定義視圖,並且咱們能夠稍微更改代碼以建立另外一個由Oleg Frolov設計的Swicher小部件。僅需將視圖輪廓從圓角矩形更新爲圓形,並禁用平移動畫。就是這麼簡單。

swicherX.gif

Talk is Cheep,Just show Code

隨意獲取GitHub上的源代碼,查看個人其餘實現,別忘了嘗試一下!
Github: https://github.com/bitvale/Switcher

以上就是所有內容,感謝你的閱讀,最後,別忘了點贊和收藏!

若是你喜歡個人文章,就關注下個人公衆號 Android技術雜貨鋪 、 簡書 或者Github!
微信公衆號:Android技術雜貨鋪

簡書:https://www.jianshu.com/u/351...

GitHub:https://github.com/pinguo-zho...

掘金:https://juejin.im/user/56949a...

相關文章
相關標籤/搜索