最近逛Dribbble
的時候,看到了一個很是酷的Switcher
動畫,特別喜歡,本想着試着用代碼在Android平臺來實現一下,沒想到已經有實現的版本,而且做者還寫了文章分享,思路清晰,各個實現關鍵點都講的特別清楚,所以就譯誠中文,分享你們,正如做者最後所說,你們必定要運行試試,效果很是贊!android
原做者:Alexander Kolpakov 譯者:依然範特稀西 地址:http://suo.im/60UJjTgit
最近,我寫了一篇關於實現Dribbble上的一個漂亮設計的文章。獲得了不少積極的反饋,對我來講,這給了我很大的動力。我很是高興能得到這些反饋,同時我也很樂意分享個人經驗。github
在本文中,咱們將嘗試逐步實現由Oleg Frolov
建立的另外一個精美的動畫。這與上一篇文章中的複雜動畫UI無關,它是一個自定義小控件。可是它有着很是精美漂亮的動畫設計,以下所示:web
乍一看,實現這樣的切換彷佛並不簡單,但我認爲那是由於動畫很是漂亮。如 你所見,建立相同的動畫並不難。讓咱們一步一步地來實現它。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)
方法,咱們須要三個動畫:編輯器
一、switcherAnimator
: 切換器圖標動畫,從白色矩形到圓形,反之亦然ide
二、translateAnimator
: 爲切換器圖標從左到右的過渡設置動畫,反之亦然;
三、colorAnimator
: 將顏色從綠色(選中)更改成紅色,反之亦然。
讓咱們先看一下switcherAnimator
動畫,設置0
爲動畫的開始值,1
爲動畫的結束值。
// ...
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
來實現反彈效果,這很是適合咱們的動畫場景,不瞭解的能夠看一下這片文章:evgenii.com/blog/spring…,它解釋了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
,是由於咱們須要平滑的動畫,而且第一個方法有優點,詳情請看:stackoverflow.com/questions/2…
translateAnimator
的工做方式相同,可是會更新Swicher
圖標的x
位置。
如你所見,咱們的白色圓圈就像百吉餅。咱們有2種製做方法:
我選擇較簡單的一種。
這一切,沒什麼難的!咱們如今有一個漂亮的自定義小控件而且帶有精美的動畫!
如今,咱們可使用任何類型的動畫來建立自定義視圖,並且咱們能夠稍微更改代碼以建立另外一個由Oleg Frolov
設計的Swicher
小部件。僅需將視圖輪廓從圓角矩形更新爲圓形,並禁用平移動畫。就是這麼簡單。
隨意獲取GitHub上的源代碼,查看個人其餘實現,別忘了嘗試一下! Github: github.com/bitvale/Swi…
以上就是所有內容,感謝你的閱讀,最後,別忘了點贊和收藏!
若是你喜歡個人文章,就關注下個人公衆號 Android技術雜貨鋪 、 簡書 或者Github! 微信公衆號:Android技術雜貨鋪
簡書:www.jianshu.com/u/35167a70a…
GitHub:github.com/pinguo-zhou…