Reputation: 434
I'm using this extension function to increase click area:
fun View.increaseHitArea() {
val parent = parent as View
parent.doOnLayout {
val rect = Rect()
getHitRect(rect)
rect.top -= 50
rect.left -= 50
rect.bottom += 50
rect.right += 50
parent.touchDelegate = TouchDelegate(rect, this)
}}
And in the fragment:
binding.button1.increaseHitArea()
binding.button2.increaseHitArea()
binding.button3.increaseHitArea()
But it gets applied to the last view (button) only, I want to apply this to all of them, what am I missing?
Upvotes: 0
Views: 68
Reputation: 19582
The TouchDelegate
is applied to the parent view, and a View
can only have one TouchDelegate
. It's basically handling the touch events for that area you define, and passing them on to the delegate (which passes them to the child view).
You'll either need to nest each Button
inside a larger parent View
(so each button has its own parent to add a delegate to), or write your own delegate class that can handle multiple children - which is obviously a lot more complicated! The source for TouchDelegate
is here if it helps.
Or you could try doing something with intercepting touch events on the parent view, and if they're clicks within the area you want, you can call performClick()
on the appropriate child view. I haven't done this and I feel like it could get a bit complex, since you need to avoid swallowing other touch events. And it won't play nice with accessibility features like explore by touch unless you implement the correct rect handling for the view hierarchy, as far as I'm aware
Honestly sticking each in its own FrameLayout
or something (with layout_gravity
on the button set to center
) and applying delegates to those is the easiest answer.
Or you can create a View
that's positioned above your button (both within the same parent), and set the delegate on that - so it's like an invisible touch area on top of your button, instead of something it has to be nested inside. Bear in mind getHitRect()
gives you coordinates within the parent, so you might need to translate that to coordinates within your touch-catching View
. The easiest way to handle it is just to make the View
fill the parent, so their coordinates match:
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="One"
/>
<View
android:id="@+id/touchCatcher1"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
The limitation here is that your View
will be limited to the size of its parent, so if your button is right against the edge of its parent layout (say in the corner of a CardView
) then you can't add a View
in the same layout that will extend past its bounds. It might be possible to do something like that with clipping etc, but you might have to adjust the Rect
coordinates.
The other option is to nest the View
outside that layout, so it's not limited by those boundaries. Except now your issue is the coordinates inside the View
and inside the Button
's parent don't match, so you'll have to adjust the coords from getHitRect
to line up properly. At that point, you might just want to use that Rect's width
and height
to create a new Rect
in the centre of your View
I know that's all a bit complex - there's no easy way that covers every situation, but you have options!
Upvotes: 2