Choosing Between android.graphics.Rect and RectF for Custom View Hit Detection
Android developers face a trade-off between integer-based Rect and float-based RectF for touch hit detection. This guide compares the options and shows a code snippet to validate the choice.
23 Jan 2026, 13:56 UTC

Decision Context
When building a custom view that responds to touch events, you must choose how to represent its touchable area. Android provides android.graphics.Rect, which uses integer coordinates, and android.graphics.RectF, which uses floating-point coordinates. The choice affects hit-test accuracy, CPU cost, and behavior on screens with different densities, especially when views are scaled or transformed.
Constraints and Trade-offs
- Precision:
Rectrounds coordinates to whole pixels;RectFretains sub-pixel values. - Performance: Integer comparisons are generally faster and are often inlined by the runtime; floating-point operations cost more on older CPUs.
- Memory: Both classes store four fields, so a single instance has a similar footprint. The difference appears in temporary allocations and library helper calls that may favor one type over the other.
- Screen density: Integer rounding can shift a touch target by a pixel on high-density screens, causing misalignment with drawn content.
- Transformations: Scaling, rotation, or translation can create sub-pixel boundaries that
Rectcannot represent exactly. - Thread safety: Both classes are mutable. Reusing one instance across threads without copying can cause race conditions.
Comparison Table
| Aspect | Rect (int) | RectF (float) |
|---|---|---|
| Coordinate type | int | float |
| Precision | Pixel-level, rounded | Sub-pixel |
| Hit-test speed | Faster integer comparisons | Slower floating-point operations |
| Instance size | Four int fields | Four float fields |
| Best for | Unscaled views, high-frequency touch on low-end hardware | Scaled or transformed views, high-density screens |
| Misalignment risk | Higher on high-DPI screens | Lower |
When to Use Rect
Use Rect when the view is drawn at its natural size without scaling or rotation, and when the hit test runs inside a tight loop, such as a game or a gesture recognizer processing many events per second. Integer containment checks avoid floating-point rounding and work well on lower-end devices.
When to Use RectF
Use RectF when the view is scaled, rotated, or translated, or when the app targets high-density screens where a one-pixel rounding error matters. Float coordinates preserve the exact transformed boundary and reduce the chance of a touch being reported outside the visible area.
Concrete Implementation and Validation
The following custom view stores both an integer and a float rectangle and toggles between them for hit testing. It logs the result so you can compare behavior on different devices.
public class HitTestView extends View {
private final Rect hitRectInt = new Rect();
private final RectF hitRectFloat = new RectF();
private boolean useFloat = false;
public HitTestView(Context context) { super(context); init(); }
public HitTestView(Context context, AttributeSet attrs) { super(context, attrs); init(); }
public HitTestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
DisplayMetrics metrics = getResources().getDisplayMetrics();
int widthPx = (int) (200 * metrics.density);
int heightPx = (int) (200 * metrics.density);
hitRectInt.set(0, 0, widthPx, heightPx);
hitRectFloat.set(0f, 0f, widthPx * 1.5f, heightPx * 1.5f);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
boolean inside;
if (useFloat) {
inside = hitRectFloat.contains(x, y);
} else {
inside = hitRectInt.contains((int) x, (int) y);
}
Log.d("HitTest", "Touch at (" + x + "," + y + ") inside? " + inside);
return true;
}
public void setUseFloat(boolean useFloat) {
this.useFloat = useFloat;
}
}
To validate, attach this view to an activity, toggle useFloat, and tap near the rectangle edges. Log the containment result for each mode. On high-density screens, RectF may report touches inside that Rect misses because of integer rounding. Do not share the same rectangle instance across threads; create a copy or confine it to the UI thread.
Performance Check
Use Android Studio CPU Profiler to record a burst of touch events and compare time spent in Rect.contains versus RectF.contains. The integer path is typically cheaper, but the difference matters mainly in high-frequency loops. Allocate the rectangle once in the view constructor rather than inside onTouchEvent to avoid garbage collection pressure.
Summary
Choose Rect when:
- The view is not scaled or transformed.
- Hit-test speed is critical on low-end hardware.
- Screen density is moderate.
Choose RectF when:
- The view undergoes scaling, rotation, or translation.
- High-density screens require sub-pixel accuracy.
- Visual alignment between touch target and drawn content is important.
Keep rectangle instances thread-confined or clone them before sharing.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.