Skip to content

Instantly share code, notes, and snippets.

@rcgroot
Created November 3, 2014 08:48
Show Gist options
  • Save rcgroot/cf30c81e5492a8afd88b to your computer and use it in GitHub Desktop.
Save rcgroot/cf30c81e5492a8afd88b to your computer and use it in GitHub Desktop.
Enlarge the touch targets of small views in Android
import android.content.Context;
import android.graphics.Rect;
import android.view.TouchDelegate;
import android.view.View;
/**
* <p>
* Ensures minimum hitbox size of small touch targets. For example:
* <p>
* <code>
* TouchDelegateAdjustment.adjustTouchSize(getActivity(), smallView);<br>
* </code>
*
* @see #adjustTouchSize(Context, View)
* @version 2
*/
public class TouchDelegateAdjustment implements Runnable
{
// 50 dp is about 9 mm in on screen size
final private static int MIN_TOUCH_WIDTH_DP = 50;
final private static int MIN_TOUCH_HEIGHT_DP = 50;
private View delegate;
private int topPadding;
private int bottomPadding;
private int leftPadding;
private int rightPadding;
/**
* Constructor: Increase the hitbox to minimum of about 9mm by 9mm size with the delegate in the middle.
*
* @param ctx The context from which to retrieve the screen density information
* @param smallView The view on which a alter the hitbox
*/
public TouchDelegateAdjustment(Context ctx, View smallView)
{
this(ctx, smallView, MIN_TOUCH_WIDTH_DP, MIN_TOUCH_HEIGHT_DP);
}
/**
* Constructor: Increase the hitbox to minimum of about 9mm by 9mm size with the delegate in the middle.
*
* @param ctx The context from which to retrieve the screen density information
* @param smallView The view one which a alter the hitbox
* @param minWidth Minimum width of the hit rects in dip
* @param minHeight Minimum height of the hit rects in dip
*/
public TouchDelegateAdjustment(Context ctx, View smallView, int minWdith, int minHeight)
{
this.delegate = smallView;
int minimumTouchWidth = (int) (minWdith * ctx.getResources().getDisplayMetrics().density + 0.5f);
int minimumTouchHeight = (int) (minHeight * ctx.getResources().getDisplayMetrics().density + 0.5f);
Rect touchRect = new Rect();
smallView.getHitRect(touchRect);
int heightPadding = (minimumTouchHeight - touchRect.height()) / 2;
int widthPadding = (minimumTouchWidth - touchRect.width()) / 2;
this.topPadding = heightPadding;
this.bottomPadding = heightPadding;
this.leftPadding = widthPadding;
this.rightPadding = widthPadding;
}
/**
* Posted in the parent's message queue to make sure the parent lays out its children before we call getHitRect()
*/
public void run()
{
View parent;
try
{
parent = (View) delegate.getParent();
}
catch (ClassCastException e)
{
throw new IllegalArgumentException("Only Views with a View as parent can have touch area enlarged", e);
}
// Construct a new Rectangle and let the Delegate set its values
Rect touchRect = new Rect();
delegate.getHitRect(touchRect);
// Modify the dimensions of the Rectangle
// Padding values below zero are replaced by zeros
touchRect.top -= Math.max(0, topPadding);
touchRect.bottom += Math.max(0, bottomPadding);
touchRect.left -= Math.max(0, leftPadding);
touchRect.right += Math.max(0, rightPadding);
// Now we are going to construct the TouchDelegate
TouchDelegate touchDelegate = new TouchDelegate(touchRect, delegate);
// And set it on the parent
parent.setTouchDelegate(touchDelegate);
}
/**
* Convenience method to initialize, connect and run the enlarger
*
* @param ctx The context from which to retrieve the screen density information
* @param smallView The view on which a alter the hitbox
* @see #TouchDelegateAdjustment(Context, View)
*/
static void adjustTouchSize(Context ctx, View smallView)
{
View parent = (View) smallView.getParent();
parent.post(new TouchDelegateAdjustment(ctx, smallView));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment