I have a UIView
, and the user can tap the UIView
to 'select' or highlight the in-app 'thing' that it represents. I use CGRectContainsPoint(thing.frame,tapPoint)
to achieve this, where thing.frame
is the frame of the UIView
, and tapPoint
is the tapped point from a UITapGestureRecognizer
. This works perfect.
..except when UIView
is rotated by setting the transform
property (with a CGAffineTransform
value). When the UIView
is rotated like this, the frame
becomes a flat square that encapsulates the rotated view.
Here is an illustration of the problem (frame property is labeled A, and the visual UIView
bounds
are labeled B):
When NOT Rotated
+------------------+
| A == B |
+------------------+
When Rotated
+-----------------+
| A . |
| . . |
| . . |
| . . |
| . B . |
| . . |
| . . |
| . |
+-----------------+
I want to capture taps that are within the bounds of rect B
(the true bounds of UIView
, rotated), but NOT when they're only within rect A
(the value of the frame
property of UIView
) and not B
.
How might I calculate whether a given tap point is within the true bounds/frame/borders of the rotated UIView
? Is there a convenience method for this? Or would I need to calculate the coordinates and dimensions of B
using my own geometry?
(If the latter, please include a suggestion so we can make the answer as complete as possible. Thanks!)
You're discovering the one fundamental stumbling block that everybody has when they first work for frame and bounds.
Frame is the smallest possible (non-rotated) rectangle in which a view fits in, taking into account transformation. Meaning, if you were to test for touches, you could log in the available space around the view so long as it was within that smallest possible rectangle.
For the visual, imagine the blue square is a transformed
UIView
. The blue border around the view represents it's frame. Notice how, even though the view is transformed, that it's frame remains un-transformed and in standard position. The green area represents the areas that are touchable ifframe
is passed instead ofbounds
:Bounds, on the other hand, represents the reciever's rectangle with respect to itself, taking into account transformations, and so testing for points in the view by passing bounds (after a
-convertPoint:toView:
call) will correctly return whether or not a given touch (point) intersects the view.here is code, viewB is target view, viewA is source view that containing the point.
I came up with this answer as I wanted a full code response explained. If anyone needs the code, for the sake of completeness, this is how I ended up calculating if a view (containerView) is fully contained in another view (view):