Android 控件自動貼邊實現實例詳解
正文
最近接到個需求,需要在用戶與App交互時,把SDK中之前實現過的懸浮控件貼邊隱藏,結束交互後延遲一段時間再自動顯示。本篇文章介紹一下實現的思路。
判斷交互
用戶與App交互、結束交互可以通過監聽觸摸事件來實現。建議使用的Activity
的dispatchTouchEvent
,Activity
下的所有觸摸事件分發時都會回調此方法,代碼如下:
class AutoEdgeHideActivity : BaseGestureDetectorActivity() { override fun dispatchTouchEvent(ev: MotionEvent): Boolean { when (ev.action) { MotionEvent.ACTION_DOWN -> { // 手指按下,開始本次交互 // 在此實現隱藏邏輯 } MotionEvent.ACTION_UP -> { // 手指抬起,結束本次交互 // 在此實現延遲顯示功能 } } return super.dispatchTouchEvent(ev) } }
隱藏與顯示
想要實現的效果是當用戶與App交互時,懸浮控件平移貼邊,但保留一部分顯示。結束交互延遲一段時間後,懸浮控件平移回原來的位置。
此處通過ValueAnimator
來實現,計算好控件的起始和結束位置,然後改變控件的x坐標,代碼如下:
private fun xCoordinateAnimator(view: View, startX: Float, endX: Float) { val animator = ValueAnimator.ofFloat(startX, endX) animator.addUpdateListener { // 不斷更改控件的X坐標 view.x = it.animatedValue as Float } // 設置插值器,速度由快變慢 animator.interpolator = DecelerateInterpolator() // 設置動畫的持續時間 animator.duration = 500 animator.start() }
示例
整合之後做瞭個示例Demo,完整代碼如下:
class AutoEdgeHideActivity : BaseGestureDetectorActivity() { private lateinit var binding: LayoutAutoEdgeHideActivityBinding private var widthPixels: Int = 0 private val autoShowInterval = 2 private var interacting = false private var hidden = false private var lastPositionX: Float = 0f private val handler = Handler(Looper.myLooper() ?: Looper.getMainLooper()) private val autoShowRunnable = Runnable { autoShow() } @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.layout_auto_edge_hide_activity) widthPixels = resources.displayMetrics.widthPixels binding.includeTitle.tvTitle.text = "AutoEdgeHideExample" binding.vFloatView.setOnClickListener { if (hidden) { // 當前為隱藏狀態,先顯示 // 把之前的延遲線程先取消 handler.removeCallbacks(autoShowRunnable) autoShow() Toast.makeText(this, "手動顯示控件", Toast.LENGTH_SHORT).show() } else { // 相應正常的事件 Toast.makeText(this, "點擊瞭浮標控件", Toast.LENGTH_SHORT).show() } } } override fun dispatchTouchEvent(ev: MotionEvent): Boolean { when (ev.action) { MotionEvent.ACTION_DOWN -> { if (!checkIsTouchFloatView(ev, binding.vFloatView)) { // 起始ACTION_DOWN事件在浮標控件外,自動隱藏浮標控件,標記正在交互 interacting = true handler.removeCallbacks(autoShowRunnable) autoHide() } } MotionEvent.ACTION_UP -> { if (interacting) { // 交互結束,一定時間後自動顯示,時間可以自由配置 interacting = false handler.postDelayed(autoShowRunnable, autoShowInterval * 1000L) } } } return super.dispatchTouchEvent(ev) } /** * 檢查是否觸摸浮標控件 */ private fun checkIsTouchFloatView(ev: MotionEvent, view: View): Boolean { val screenLocation = IntArray(2) view.getLocationOnScreen(screenLocation) val viewX = screenLocation[0] val viewY = screenLocation[1] return (ev.x >= viewX && ev.x <= (viewX + view.width)) && (ev.y >= viewY && ev.y <= (viewY + view.height)) } private fun autoShow() { if (hidden) { hidden = false binding.vFloatView.let { xCoordinateAnimator(it, it.x, lastPositionX) } } } private fun autoHide() { if (!hidden) { hidden = true binding.vFloatView.let { // 記錄一下顯示狀態下的x坐標 lastPositionX = it.x // 隱藏時的x坐標,留一點控件的邊緣顯示(示例中默認控件在屏幕右側) val endX = widthPixels - it.width * 0.23f xCoordinateAnimator(it, lastPositionX, endX) } } } private fun xCoordinateAnimator(view: View, startX: Float, endX: Float) { val animator = ValueAnimator.ofFloat(startX, endX) animator.addUpdateListener { view.x = it.animatedValue as Float } animator.interpolator = DecelerateInterpolator() animator.duration = 500 animator.start() } }
效果如圖:
以上就是Android 控件自動貼邊實現實例詳解的詳細內容,更多關於Android 控件自動貼邊的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 關於Android觸摸事件分發的原理詳析
- android控件實現單擊拖動效果
- Android自定義View實現拖動自動吸邊效果
- ViewPager2滑動沖突解決方案
- Android事件分發機制全面解析