Guide
Diagnosing and Fixing Incorrect Android Rect Usage Causing UI Clipping and Touch Issues
Learn how to spot empty or inverted Rect objects that break hit‑testing, drawing, or layout, and follow a step‑by‑step guide to verify, fix, and escalate the problem.
Published by Tasadduq Burney
07 Jul 2026, 13:06 UTC
3 min33.6K views0

Recognizable Symptoms
When a view stops receiving touch events, appears clipped, or reports bizarre bounds in Layout Inspector, the root cause is often a malformed android.graphics.Rect used for hit‑testing, clipping, or drawing.
Cause & Diagnosis Table
| Symptom | Typical Cause | What to Look For |
|---|---|---|
| Touch events not delivered to a view | Rect from getHitRect() or manual intersect/union has width ≤ 0 or height ≤ 0 (empty) | Check rect.isEmpty() or rect.width() <= 0 || rect.height() <= 0 |
| Drawing appears clipped or missing | Rect passed to Canvas.clipRect() or drawRect() has negative width/height or left > right/top > bottom | Inspect rect.left, rect.right, rect.top, rect.bottom for inverted values |
| Layout Inspector shows (0,0,0,0) or wild bounds | Manual arithmetic (e.g., rect.left += deltaX) performed without re‑validating ordering | After any mutation, verify left < right && top < bottom |
Ordered Checks
- Locate Rect usage – Search for
getHitRect(),intersect(),union(),clipRect(),drawRect(), or direct field modifications. - Add runtime logging – Immediately before each use, insert:
Log.d("RectCheck", "rect=L:" + rect.left + " T:" + rect.top + " R:" + rect.right + " B:" + rect.bottom +
" w:" + rect.width() + " h:" + rect.height() + " empty:" + rect.isEmpty());
- Run the app and reproduce the issue – Look for log lines where width/height ≤ 0 or
isEmpty()is true. - Debugger inspection – Set a breakpoint on the line that modifies the Rect (e.g., after
intersect) and verifyleft < right && top < bottomin the Variables view. - Unit‑test validation – Create a test that calls the same intersect/union logic with known inputs and asserts:
@Test
public void intersectProducesValidRect() {
Rect a = new Rect(10, 10, 30, 30);
Rect b = new Rect(20, 20, 40, 40);
Rect out = new Rect(a);
out.intersect(b);
assertFalse(out.isEmpty());
assertTrue(out.width() > 0 && out.height() > 0);
}
Fixes Tied to Findings
- Empty Rect from intersect/union – After calling
intersectorunion, guard the result:
Rect hit = new Rect();
view.getHitRect(hit);
if (!hit.isEmpty()) {
// use hit for hit‑testing
}
- Inverted coordinates – Normalize before drawing or clipping:
if (rect.left > rect.right) {
int tmp = rect.left; rect.left = rect.right; rect.right = tmp;
}
if (rect.top > rect.bottom) {
int tmp = rect.top; rect.top = rect.bottom; rect.bottom = tmp;
}
// now safe to pass to Canvas
- Manual arithmetic mistakes – Encapsulate updates in a helper that re‑validates:
void shiftRect(Rect r, int dx, int dy) {
r.left += dx; r.right += dx;
r.top += dy; r.bottom += dy;
if (r.left > r.right) { int t = r.left; r.left = r.right; r.right = t; }
if (r.top > r.bottom) { int t = r.top; r.top = r.bottom; r.bottom = t; }
}
Escalation Criteria
If the above checks and fixes do not resolve the symptom:
- Verify that no other thread is mutating the same Rect instance concurrently (Rect is not thread‑safe).
- Check custom view subclasses that override
getHitRect()oronTouchEventfor logic that replaces the Rect after validation. - Consider using
RectFwith floating‑point precision if sub‑pixel calculations are causing rounding to zero size. - File a bug with a minimal reproducible example, attaching the log output and debugger screenshots showing the Rect state before the failing API call.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.