最近逛Dribbble
的時候,看到了一個很是酷的Switcher
動畫,特別喜歡,本想着試着用代碼在Android平臺來實現一下,沒想到已經有實現的版本,而且做者還寫了文章分享,思路清晰,各個實現關鍵點都講的特別清楚,所以就譯誠中文,分享你們,正如做者最後所說,你們必定要運行試試,效果很是贊!android
原做者: Alexander Kolpakov
譯者: 依然範特稀西
地址: http://suo.im/60UJjT
最近,我寫了一篇關於實現Dribbble上的一個漂亮設計的文章。獲得了不少積極的反饋,對我來講,這給了我很大的動力。我很是高興能得到這些反饋,同時我也很樂意分享個人經驗。git
在本文中,咱們將嘗試逐步實現由Oleg Frolov
建立的另外一個精美的動畫。這與上一篇文章中的複雜動畫UI無關,它是一個自定義小控件。可是它有着很是精美漂亮的動畫設計,以下所示:github
乍一看,實現這樣的切換彷佛並不簡單,但我認爲那是由於動畫很是漂亮。如 你所見,建立相同的動畫並不難。讓咱們一步一步地來實現它。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
小部件。僅需將視圖輪廓從圓角矩形更新爲圓形,並禁用平移動畫。就是這麼簡單。
隨意獲取GitHub上的源代碼,查看個人其餘實現,別忘了嘗試一下!
Github: https://github.com/bitvale/Switcher
以上就是所有內容,感謝你的閱讀,最後,別忘了點贊和收藏!
若是你喜歡個人文章,就關注下個人公衆號 Android技術雜貨鋪 、 簡書 或者Github!
微信公衆號:Android技術雜貨鋪簡書:https://www.jianshu.com/u/351...