【android学习笔记】不可用功能被用户点击后触发不可用提醒
前言
因为不可用功能的view被设置了 isEabled = false,所以是无法触发 onClicked,另外不可用功能被标记之后无法拦截自定义触摸事件。
一系列原因下来,所以不可用事件最好是监听用户的触摸,在这一道关卡无差别拦截下来,不仅方便监控全局触摸事件,还可以省掉自定义触摸事件对不可用情况下的定义,省掉了一大部分代码
重写dispatchTouchEvent
override fun dispatchTouchEvent(ev: MotionEvent): Boolean { // 重写触摸拦截
when (ev.action) {
MotionEvent.ACTION_DOWN -> { // 如果用户按下
val found = findViewAt(window.decorView, ev.rawX, ev.rawY) // 找到用户按到的view(最小的子view)
if (found != null) {
Log.d(TAG, "DOWN TOUCH: $found")
val target = getUnavailableClickTarget(found) // 查看该view有无打上不可用标签(需要查看父view等)
if (target != null) { // 如果被打上不可用标签
unavailableTarget = target // 记录不可用
return true // 退出
}
}
}
MotionEvent.ACTION_UP -> { // 如果用户抬手
if (unavailableTarget != null) { // 看到了不可用记录
unavailableTarget = null // 清掉不可用标记
Toast.makeText(this@MainActivity
, "该功能当前不可用!", Toast.LENGTH_SHORT).show() // 弹出提醒
return true // 退出
}
}
MotionEvent.ACTION_MOVE -> { // 如果用户持续触摸(在按下与抬手之间)
if (unavailableTarget != null) { // 拦截掉,不用管
return true
}
}
MotionEvent.ACTION_CANCEL -> { // 用户触摸被取消
unavailableTarget = null // 清空不可用记录
}
}
return super.dispatchTouchEvent(ev)
}
一些工具方法
findViewAt,找到用户按到的最小的view
private fun findViewAt(root: View, x: Float, y: Float): View? { // 用户所在的根View,用户所在的绝对坐标x,y
if (root.visibility != View.VISIBLE) return null // 如果不可见就跳过
if (root is ConstraintHelper) return null // flow布局会重定义子控件id,过滤掉
val location = IntArray(2)
root.getLocationOnScreen(location) // 获取当前view的位置
val left = location[0]
val top = location[1]
val right = left + root.width
val bottom = top + root.height // 计算出当前view的上下左右
if (x < left || x > right || y < top || y > bottom) return null // 如果触控位置不在当前view内就过滤掉
if (root is ViewGroup) { // 如果当前view还有子view
for (i in root.childCount - 1 downTo 0) {
val child = root.getChildAt(i) // 遍历子view
val found = findViewAt(child, x, y) // 找最小子view
if (found != null) return found // 找到就返回
}
}
return root // 找不到最小子view就返回当前view(已经是最小的了)
}
getUnavailableClickTarget,查看该view及父view有无不可用标签
private fun getUnavailableClickTarget(view: View): View? {
var current: View? = view // 当前view
while (current != null) {
val isAvailable = current.getTag(R.id.tag_feature_available) as? Boolean // 当前view有没有打上不可用标签
if (isAvailable == false) { // 不可用
return current // 返回当前view
}
val parent = current.parent // 找到当前view的父view
current = if (parent is View) parent else null // 递归,让当前view变成父view
}
return null
}

不可用功能被用户点击后触发不可用提醒
浙公网安备 33010602011771号