How to use CGRectContainsPoint () with rotated UIView

I have a UIView , and the user can click UIView on "select" or select the "thing" in the application that it represents. To achieve this, I use CGRectContainsPoint(thing.frame,tapPoint) , where thing.frame is a UIView frame and tapPoint is a point with a point from UITapGestureRecognizer . It works great.

.. unless the UIView rotated by setting the transform property (with a value of CGAffineTransform ). When the UIView rotates like this, frame becomes a flat square that encapsulates the rotated view.

Here is an illustration of the problem (the frame property is marked as A, and the visual UIView bounds indicated by B):

When NOT rotated

 +------------------+ | A == B | +------------------+ 

During rotation

 +-----------------+ | A . | | . . | | . . | | . . | | . B . | | . . | | . . | | . | +-----------------+ 

I want to capture cranes that are within rect B (true UIView borders UIView rotated), but NOT when they are only within rectangle A (the value of the frame property is UIView ), and not B

How can I calculate if a given transition point is within the true borders / frames / borders of the rotated UIView ? Is there a convenience method for this? Or do I need to calculate the coordinates and dimensions of B using my own geometry?

(If the latter, please include a sentence so that we can make the answer as complete as possible. Thank you!)

+4
source share
3 answers

You discover one fundamental stumbling block that everyone has when they first work for frames and boundaries.

A frame is the smallest possible (non-rotating) rectangle in which a view is inserted, taking into account the transformation. Meaning, if you were to test touches, you could enter the free space around the view while it was within the smallest possible rectangle.

For visual presentation, suppose the blue square is a transformed UIView . The blue frame around the presentation represents its frame. Note that although the view is being transformed, it remains unchanged and is in its default position. The green area represents areas that are tangible if frame is passed instead of bounds :

frame

Borders, on the other hand, represent the receiver's rectangle relative to itself, taking into account the transformations, and therefore testing points in the view by passing the boundaries (after calling -convertPoint:toView: will correctly return, regardless of whether the given contact (point ) crosses the view.

+10
source

here the code, viewB is the target view, viewA is the source view containing the point.

 if(CGRectContainsPoint(viewB.bounds, [viewA convertPoint:point toView:viewB])){ //... } 
+2
source

I came up with this answer because I need a complete code answer. If someone needs code, for completeness, this is how I ended up calculating if the view (containerView) is completely contained in another view (view):

 -(BOOL)viewIsFullyContained:(UIView*)view{ // get the inner rectangle corners in the view coordinate system CGPoint upperLeft = [self.containerView convertPoint:self.containerView.bounds.origin toView:view]; CGPoint upperRight = [self.containerView convertPoint:CGPointMake(self.containerView.bounds.origin.x + self.containerView.bounds.size.width, self.containerView.bounds.origin.y) toView:view]; CGPoint lowerLeft = [self.containerView convertPoint:CGPointMake(self.containerView.bounds.origin.x, self.containerView.bounds.origin.y + self.containerView.bounds.size.height) toView:view]; CGPoint lowerRight = [self.containerView convertPoint:CGPointMake(self.containerView.bounds.origin.x + self.containerView.bounds.size.width, self.containerView.bounds.origin.y + self.containerView.bounds.size.height) toView:view]; // Check whether all of the corners are fully contained in the view. BOOL upperLeftIsContained = CGRectContainsPoint(view.bounds, upperLeft); BOOL upperRightIsContained = CGRectContainsPoint(view.bounds, upperRight); BOOL lowerLeftIsContained = CGRectContainsPoint(view.bounds, lowerLeft); BOOL lowerRightIsContained = CGRectContainsPoint(view.bounds, lowerRight); NSLog(@"Checking for (%i/%i/%i/%i)",upperLeftIsContained,upperRightIsContained,lowerLeftIsContained,lowerRightIsContained); return (upperRightIsContained && upperRightIsContained && lowerRightIsContained && lowerLeftIsContained); } 
0
source

All Articles