Fast Hit‑Testing with Android’s Rect.intersect(): A Practical Guide
Learn how Android’s Rect.intersect() simplifies hit‑testing for UI and games. A step‑by‑step Kotlin example, performance trade‑offs, and when to switch to a custom collision system.
12 Jul 2026, 11:29 UTC

The Hit‑Testing Problem
In almost every Android UI or 2‑D game you need to know whether a user touch, a button, or a sprite overlaps another rectangular area. The naive way is to compare four coordinates and write custom math for each pair. That quickly becomes error‑prone and harder to maintain. Android supplies a lightweight helper: Rect.intersect().
How Rect.intersect() Works
A Rect holds four integer fields: left, top, right, bottom. The intersect() method comes in two flavors:
boolean intersect(Rect other)– mutates the receiver to the intersection of itself andother, returnstrueif the rectangles overlap.boolean intersect(int left, int top, int right, int bottom)– same idea but takes raw coordinates.
Internally it performs integer comparisons and assigns the max of the left/top values and the min of the right/bottom values. Because all values are integers, the operation is fast and has no heap allocation.
Working Example in Kotlin
Below is a minimal snippet you can drop into an Android unit test or a View subclass. It demonstrates:
- Creating two
Rectobjects. - Calling
intersect()and capturing the boolean. - Inspecting the mutated receiver.
// 1. Define two rectangles – coordinates are in pixels.
val buttonRect = Rect(10, 10, 100, 100) // left, top, right, bottom
val touchRect = Rect(50, 50, 150, 150)
// 2. Perform intersection.
val hit = buttonRect.intersect(touchRect)
// 3. Log the result – expect true and a new bounds of (50, 50, 100, 100).
Log.d("HitTest", "hit=$hit, buttonRect=$buttonRect")
To verify:
- Run the snippet in an Android unit test or a simple
Activity. - Check the log output. It should read something like
hit=true, buttonRect=Rect[50, 50, 100, 100]. - If the values differ, double‑check that both rectangles are expressed in the same coordinate system (screen pixels vs. density‑independent pixels).
Remember: intersect() mutates the receiver. If you need the original bounds later, make a copy before calling:
val original = Rect(buttonRect)
buttonRect.intersect(touchRect)
// original still holds the original values.
When to Avoid intersect()
| Scenario | Why It’s Problematic |
|---|---|
| Large‑scale collision detection (hundreds of sprites) | Each call copies the receiver; a tight loop can become a GC hotspot. |
| Floating‑point sizes or high‑density scaling | Rect uses integers; you must convert to the same unit before intersecting. |
| Need to preserve original bounds | Method mutates; copying adds overhead. |
In those cases, consider a spatial index (quad‑tree, grid) or a custom struct that keeps immutable bounds and uses a static intersects(a, b) helper that doesn’t modify either rectangle.
Takeaway
For most UI hit‑testing and simple sprite collision checks, Rect.intersect() is a quick, built‑in, and reliable choice. It keeps your code concise, eliminates manual math, and integrates with Android’s rendering pipeline. Just be mindful of its mutating behavior, integer‑only coordinates, and the performance cost when scaling to hundreds of objects. When those limits are reached, move to a more specialized collision system.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.