Android 5.0中引入了不少炫酷的動畫效果,Circular Reveal即是其中一種。使用起來很簡單,但效果倒是意想不到的炫酷,讓你的app更有逼格。java
廢話不說,下面的gif圖中使用Circular Reveal動畫實現跳轉到搜索頁的效果。gif圖壓縮寬高比失真了,不過效果還在。源碼在最下面,能夠下載體驗下。
android
當您顯示或隱藏一組 UI 元素時,揭露動畫可爲用戶提供視覺連續性。git
ViewAnimationUtils.createCircularReveal()方法讓您可以爲裁剪區域添加動畫以揭露或隱藏視圖。github
* @param view The View will be clipped to the animating circle.
* @param centerX The x coordinate of the center of the animating circle, relative to
* <code>view</code>.
* @param centerY The y coordinate of the center of the animating circle, relative to
* <code>view</code>.
* @param startRadius The starting radius of the animating circle.
* @param endRadius The ending radius of the animating circle.
*/
public static Animator createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius) {
return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
}複製代碼
ViewAnimationUtils.createCircularReveal()方法所執行的效果,就是將一個View裁剪成圓,而後從圓心逐漸揭露展示視圖。app
參數 | 參數說明 |
---|---|
view | 要執行動畫效果的View |
centerX | 圓心x座標 |
centerY | 圓心y座標 |
startRadius | 開始時的圓半徑 |
endRadius | 結束時的圓半徑 |
@SuppressLint("NewApi")
private fun actionOtherVisible(isShow: Boolean, triggerView: View, animView: View) {
//判斷API是否大於21
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
if (isShow) {
animView.visibility = View.VISIBLE
if (mListener != null) mListener!!.onShowAnimationEnd()
} else {
animView.visibility = View.GONE
if (mListener != null) mListener!!.onHideAnimationEnd()
}
return
}
/** * 計算 triggerView(即搜索按鈕) 的中心位置 */
val tvLocation = IntArray(2)
triggerView.getLocationInWindow(tvLocation)
val tvX = tvLocation[0] + triggerView.width / 2
val tvY = tvLocation[1] + triggerView.height / 2
/** * 計算 animView(即根佈局) 的中心位置 */
val avLocation = IntArray(2)
animView.getLocationInWindow(avLocation)
val avX = avLocation[0] + animView.width / 2
val avY = avLocation[1] + animView.height / 2
//計算寬高
val rippleW = if (tvX < avX) animView.width - tvX else tvX - avLocation[0]
val rippleH = if (tvY < avY) animView.height - tvY else tvY - avLocation[1]
//勾股定理求斜邊
val maxRadius = Math.sqrt((rippleW * rippleW + rippleH * rippleH).toDouble()).toFloat()
val startRadius: Float
val endRadius: Float
//根據展現或隱藏設置起始與結束的半徑
if (isShow) {
startRadius = 0f
endRadius = maxRadius
} else {
startRadius = maxRadius
endRadius = 0f
}
val anim = ViewAnimationUtils.createCircularReveal(animView, tvX, tvY, startRadius, endRadius)
animView.visibility = View.VISIBLE
anim.duration = DURATION
anim.interpolator = DecelerateInterpolator()
//監聽動畫結束,進行回調
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
if (isShow) {
animView.visibility = View.VISIBLE
if (mListener != null) mListener!!.onShowAnimationEnd()
} else {
animView.visibility = View.GONE
if (mListener != null) mListener!!.onHideAnimationEnd()
}
}
})
anim.start()
}複製代碼
上述代碼中註釋清楚解析了動畫參數的獲取和執行過程。ide
fun show(triggerView: View, showView: View) {
actionOtherVisible(true, triggerView, showView)
}
fun hide(triggerView: View, hideView: View) {
actionOtherVisible(false, triggerView, hideView)
}複製代碼
actionOtherVisible()方法根據傳入true/false來肯定是執行展現或隱藏動畫。佈局
在SearchFragment中,監聽第一幀的繪製,開啓動畫。其中mRootView就是根佈局View。動畫
override fun onPreDraw(): Boolean {
iv_search_search.viewTreeObserver.removeOnPreDrawListener(this);
mCircularRevealAnim.show(iv_search_search, mRootView);
return true;
}複製代碼
動畫結束調用時機:①在點擊搜索,跳轉到搜索結果界面。②物理回退鍵回退。③點擊回退按鈕ui
再以上三個地方均可以調用hide()方法,實現隱藏動畫。this
在上面配置動畫參數的過程當中,對動畫結束進行了監聽回調。調用了AnimListener接口的onHideAnimationEnd()和onShowAnimationEnd()方法,來實現回調。全部在SearchFragment中實現該接口,來監聽回調。
override fun onHideAnimationEnd() {
et_search_keyword.setText("");
dismiss();
}
override fun onShowAnimationEnd() {
if (isVisible) {
KeyBoardUtils.openKeyboard(activity, et_search_keyword);
}
}複製代碼
監聽到隱藏動畫結束的時候,調用dismiss()方法關閉該DialogFragment。監聽展示動畫結束的時候,開啓輸入法框。
就是這麼簡單,經過以上方式就能夠實現如此炫酷的效果。
Github地址:搜索頁Circular Reveal動畫