My understanding is that when you have a view that\'s too small to easily touch, you\'re supposed to use a TouchDelegate to increase the clickable region for that view.
If don't want to do it programatically then simply create transparent area around the image, If you are using image as background for the button (view).
The grey area can be transparent to increase the touch area.
In most cases, you can wrap the view that requires a larger touch area in another headless view (artificial transparent view) and add padding/margin to the wrapper view and attach the click/touch even to the wrapper view instead of the original view that has to have a larger touch area.
A bit late to the party, but after much research, I'm now using:
/**
* Expand the given child View's touchable area by the given padding, by
* setting a TouchDelegate on the given ancestor View whenever its layout
* changes.
*/*emphasized text*
public static void expandTouchArea(final View ancestorView,
final View childView, final Rect padding) {
ancestorView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
TouchDelegate delegate = null;
if (childView.isShown()) {
// Get hitRect in parent's coordinates
Rect hitRect = new Rect();
childView.getHitRect(hitRect);
// Translate to ancestor's coordinates
int ancestorLoc[] = new int[2];
ancestorView.getLocationInWindow(ancestorLoc);
int parentLoc[] = new int[2];
((View)childView.getParent()).getLocationInWindow(
parentLoc);
int xOffset = parentLoc[0] - ancestorLoc[0];
hitRect.left += xOffset;
hitRect.right += xOffset;
int yOffset = parentLoc[1] - ancestorLoc[1];
hitRect.top += yOffset;
hitRect.bottom += yOffset;
// Add padding
hitRect.top -= padding.top;
hitRect.bottom += padding.bottom;
hitRect.left -= padding.left;
hitRect.right += padding.right;
delegate = new TouchDelegate(hitRect, childView);
}
ancestorView.setTouchDelegate(delegate);
}
});
}
This is better than the accepted solution because it also allows a TouchDelegate to be set on any ancestor View, not just the parent View.
Unlike the accepted solution, it also updates the TouchDelegate whenever there is a change in the ancestor View's layout.
According to @Mason Lee comment, this solved my problem. My project had relative layout and one button. So parent is -> layout and child is -> a button.
Here is a google link example google code
In case of deleting his very valuable answer I put here his answer.
I was recently asked about how to use a TouchDelegate. I was a bit rusty myself on this and I couldn't find any good documentation on it. Here's the code I wrote after a little trial and error. touch_delegate_view is a simple RelativeLayout with the id touch_delegate_root. I defined with a single, child of the layout, the button delegated_button. In this example I expand the clickable area of the button to 200 pixels above the top of my button.
public class TouchDelegateSample extends Activity { Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.touch_delegate_view); mButton = (Button)findViewById(R.id.delegated_button); View parent = findViewById(R.id.touch_delegate_root); // post a runnable to the parent view's message queue so its run after // the view is drawn parent.post(new Runnable() { @Override public void run() { Rect delegateArea = new Rect(); Button delegate = TouchDelegateSample.this.mButton; delegate.getHitRect(delegateArea); delegateArea.top -= 200; TouchDelegate expandedArea = new TouchDelegate(delegateArea, delegate); // give the delegate to an ancestor of the view we're delegating the // area to if (View.class.isInstance(delegate.getParent())) { ((View)delegate.getParent()).setTouchDelegate(expandedArea); } } }); } }
Cheers, Justin Android Team @ Google
Few words from me: if you want expand left side you give value with minus, and if you want expand right side of object, you give value with plus. This works the same with top and bottom.
This solution was posted by @BrendanWeinstein in comments.
Instead of sending a TouchDelegate
you can override getHitRect(Rect)
method of your View
(in case that you are extending one).
public class MyView extends View { //NOTE: any other View can be used here
/* a lot of required methods */
@Override
public void getHitRect(Rect r) {
super.getHitRect(r); //get hit Rect of current View
if(r == null) {
return;
}
/* Manipulate with rect as you wish */
r.top -= 10;
}
}