一年多前寫過一篇文章, Android擴大View點擊區(qū)域, 此方法存在諸多限制,且只能對其中一個子View進行點擊范圍的擴展, 今天想到一個新的思路, 實現(xiàn)并支持擴展任意多個子View的點擊范圍,供君參考(源碼見文末)。
使用實例
binding.cv1.setOnClickListener {
ToastUtils.show("cv1 Click!!")
}
val dp20 = 20.dpToPx()
ClickAreaExpander()
.addExpandView(binding.cv1, dp20, dp20)
//.addExpandView(binding.cv2, dp20, dp20)
//.....
.expandOn(binding.touchOutView)
XML示例

預覽效果
<FrameLayout
android:id="@+id/touchOutView"
android:layout_width="match_parent"
android:layout_height="200dp">
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:background="#22000000" />
<View
android:id="@+id/cv1"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_gravity="center"
android:background="@drawable/shape_white_16" />
</FrameLayout>
源碼實現(xiàn)
class ClickAreaExpander : View.OnTouchListener {
private var touchDelegates: MutableList<TouchDelegate> = mutableListOf()
private var enable = false
private var mItems = mutableListOf<Item>()
lateinit var vg: ViewGroup
var needInit = true
fun expandOn(viewGroup: ViewGroup) {
vg = viewGroup
enable = true
vg.setOnTouchListener(this)
}
/**
* 增加需要擴寬點擊范圍的View
*
* @param view 擴充點擊/長按事件的VIew
* @param leftTop 擴寬距離,單位px
* @param rightBottom 擴寬距離,單位px
*/
fun addExpandView(view: View, leftTop: Int, rightBottom: Int): ClickAreaExpander {
mItems.add(Item(view, leftTop, rightBottom))
needInit = true
return this
}
/**
* 移除
*/
fun removeView(view: View): ClickAreaExpander {
mItems.firstOrNull { x -> x.view == view }?.let {
mItems.remove(it)
needInit = true
}
return this
}
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
event ?: return false
v ?: return false
var handle = false
if (enable) {
if (needInit) {
if (mItems.isEmpty()) {
enable = false
return false
}
initViews()
}
for (i in 0 until touchDelegates.size) {
val item = touchDelegates[i]
val h = item.onTouchEvent(event)
if (h) {
handle = true
break
}
}
}
return handle
}
fun enable(e: Boolean = true) {
enable = e
}
private fun initViews() {
needInit = false
touchDelegates.clear()
mItems.forEach {
val v = it.view
if (vg.contains(v)) {
val rect = Rect()
v.getHitRect(rect)
rect.inset(-it.leftTop, -it.rightBottom)
touchDelegates.add(0, TouchDelegate(Rect(rect), v))
}
}
}
inner class Item(val view: View, val leftTop: Int, val rightBottom: Int)
}