How to test if a point is in a view - iphone

I have a UIImageView and I have a CGPoint on the screen. I want to be able to test that point to see if it is in the UIImageView. What would be the best way to do this?

CGPoint is no good with a reference point. If your point is in window's coordinates then you can get it using
CGPoint locationInView = [imageView convertPoint:point fromView:imageView.window];
if ( CGRectContainsPoint(imageView.bounds, locationInView) ) {
// Point lies inside the bounds.
}
You may also call pointInside:withEvent: method
if ( [imageView pointInside:locationInView withEvent:nil] ) {
// Point lies inside the bounds
}

Tested in Swift 4
view.frame.contains(point)

if(CGRectContainsPoint([myView frame], point))
where point is your CGPoint and myView is your UIImageView

I'll assume you have a full-screen window (pretty reasonable, I think). Then you can transform the point from the window's coordinate space to the UIImageView's using:
CGPoint point = ...
UIWindow window = ...
UIImageView imageView = ...
CGPoint transformedPoint = [window convertPoint:point toView:imageView];
Then, you can test if the point is in the image view's frame as follows:
if(CGRectContainsPoint(imageView.frame, transformedPoint))
{
// do something interesting....
}

In Swift 3
let isPointInFrame = UIScreen.main.bounds.contains(newLocation)

Related

if([labelView.layer containsPoint:touchPoint]) not working in Xcode

Can anyone tell that, i have taken draggable label with UIPangesture when dragging and releasing mouse i am finding touch point using
CGPoint touchPoint = [panGesture locationInView:self.view];
now i want to check on which label is this label dragged.For this i am using this code
for(UILabel *labelView in self.view.subviews){
if ([labelView isMemberOfClass:[UILabel class]]) {
NSLog(#"%#",NSStringFromCGPoint(touchPoint ));
NSLog(#"%#",NSStringFromCGRect(labelView.layer.frame));
if([labelView.layer containsPoint:touchPoint]){
int i=[[labelView.subviews objectAtIndex:0] tag];
NSLog(#">>>> %d",i);
}
}
}
panGesture passed to the gesture handler method has property 'view' that points which UILabel object you've setup with the recognizer
EDIT:
*-- the answe above was wrong. Thanks Jacky for pointing me out --*
self.view's hitTest:withEvent: method would return the view at the point. Pass nil to withEvent:
if self.view has subviews other than UILabel too and you want to avoid one of those returned, call
bool CGRectContainsPoint (
CGRect rect,
CGPoint point
);
for each label. Pass frame for rect, touchpoint for point
for(UILabel *labelView in self.view.subviews){
if ([labelView isMemberOfClass:[UILabel class]]) {
if(CGRectContainsPoint(labelView.frame,touchPoint)){
int i=[[labelView.subviews objectAtIndex:0] tag];
NSLog(#">>>> %d",i);
}
}
}
EDIT:
The reason why .layer's containsPoint: didn't work:
thePoint A point in the receiver’s coordinate system.
In your code, touchPoint is in self.view's coordinate system that is different from any label's coordinate system
Thanks for replying.
This worked for me
if ([labelView.layer containsPoint:[labelView.layer convertPoint:touchPoint fromLayer:labelView.layer.superlayer]] == TRUE)
but your answer is also correct i have check that.

UIGestureRecogniser on a masked UIView?

Is there a way to know if a 'tap' is inside or outside the masked area of a UIView? I'm using CoreGraphics to mask the UIView.
So far my code goes something like this..
- (void)viewDidLoad {
UIGestureRecogniser *r = [[UIGestureRecogniser alloc] initWithTarget:self action:#selector(gestCall:)];
[self addGestureRecogniser:r];
}
- (void)gestCall:(UIGestureRecogniser *)gestRec {
if ("somthing") {
// outside of mask
} else {
// inside of mask
}
}
Thank you.
I've finally found the solution I was looking for. So for the benefit of any one trying to find is a CGPoint is inside any CGPath.
It's simple.
UIBezierPath *p = [UIBezierPath bezierPathWithCGPath:anyCGPath];
BOOL isInPath = [p containsPoint:anyCGPoint];
Basically you need to check the touch coordinate and decide whether is falls into the mask area or not. Override the hitTest:withEvent: and account for the image mask. You can use [[[self layer] presentationLayer] hitTest:aPoint] or [[[self layer] mask] hitTest:aPoint] in your overridden `-[UIView hitTest:withEvent:].
[EDIT]
Check if a user tapped near a CGPath might help to find answer to your question.
[EDIT]
Do following in your Gesture Handler to figure out to process tap or not.
Specify the center of the circle (This would be UIView.Center as CGPoint)
Specify the radius of pie chart
When user tap on the view, get the location as point - CGPoint and calculate point.x*point.x+point.y*point.y (Circle formulae) and this value must be less than or equal to the square of the radius i.e radius*radius. If this condition satisfied then your tap point is inside the circle otherwise outside.
Hope that makes clear.

Zooming a background image without zooming the overlay

I'm a beginner to the iOS development, and I'm trying to display an image (a map in fact) which need to be zoomable and pannable. My problem is that I don't know how to add an overlay which will follow the pan to always represent the same location, but won't be scaled by the zoom. There will be several overlays, and each one must be clickable.
To zoom and pan the image (map), I added my UIImageView in a UIScrollView and it works great, but I have no idea how to add this feature.
I found this thread but it is not really the same problem since his overlay is static :
UIScrollview with two images - Keeping 1 image zoomable and 1 image static (fixed size)
I've developped the same application in android, and to make this work I was converting a pixel of the map in screen coordinates thanks to the transformation matrix, and I overrode the onDraw method to display it, but I don't know how to do the same on iOS, and I don't know if this is the better solution.
Thanks for any help.
Ok so I found a way to do it, if it can helps anybody :
I added my overlay in the scrollView, with the background image (the map).
+CustomScrollView
----> UIImageView (map)
----> OverlayImageView (overlay)
In order to zoom, the custom scrollview need a delegate with the following methods :
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
//The background image with the map
return mapView;
}
//When a zoom occurs, move the overlay
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
UIImageView* overlayView = [scroll.subviews objectAtIndex:1];
float x;
float y;
float width;
float height;
//keep the width and height of the overlay
width = overlayView.frame.size.width;
height = overlayView.frame.size.height;
//Move it to stay over the same pixel of the map, and centers it
x = (self.overlay.point.x * scroll.zoomScale - width/2);
y = (self.overlay.point.y * scroll.zoomScale - height/2);
overlayView.frame = CGRectMake(x,y,width,height);
}
With this, we are saying that the zoom only occurs on the background image, but as the overlay is in the UIScrollView, it pans with it. So the only thing we need to care is to move the Overlay when the zoom change, and we know it with the scrollViewDidZoom method.
To handle the touch events, we override the touchEnded:withEvent: of CustomScrollView and we forward it to the overlay if there is only one tap. I don't show the OverlayImageView since it only override this same method (toucheEnded:withEvent:) to handle a touch on it.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
// Coordinates in map view
CGPoint point = [touch locationInView:[self.subviews objectAtIndex:0]];
//forward
if(touch.tapCount == 1){
OverlayImageView* overlayView = [self.subviews objectAtIndex:1];
CGPoint newPoint = [touch locationInView:overlayView];
BOOL isInside = [overlayView pointInside:newPoint withEvent:event];
if(isInside){
[overlayView touchesEnded:touches withEvent:event];
}
}
// zoom
else if(touch.tapCount == 2){
if(self.zoomScale == self.maximumZoomScale){
[self setZoomScale:[self minimumZoomScale] animated:YES];
} else {
CGRect zoomRect = [self zoomRectForScrollView:self withScale:self.maximumZoomScale withCenter:point];
[self zoomToRect:zoomRect animated:YES];
//[self setZoomScale:[self maximumZoomScale] animated:YES];
}
[self setNeedsDisplay];
}
}
Hope this will help.
You can put an imageView on top as an overLay and set its userInteractionEnabled property to NO. Then you have to pan it programmatically.

How can I animate the road in iPhone Xcode?

I am going to animate the road, simply calling 1 image again and again from top to bottom. Can anyone suggest how this is possible?
You'll want to look at a UIScrollView. Put a UIImageView in it, then use the following code:
-(void)scroll{
CGPoint currentPoint = scrollView.contentOffset;
CGPoint scrollPoint = CGPointMake(currentPoint.x, currentPoint.y + 1);
[scrollView setContentOffset:scrollPoint animated:NO];
if(scrollPoint.y == scrollView.contentSize.height+5)//If we've reached the bottom, reset slightly past top, to give ticker look
{
[scrollView setContentOffset:CGPointMake (0,-125)];
}
}
Run that code with a looping NSTimer and you'll be set :)

(iphone) how to set view.center when detaching a view from scroll view and adding it to another view?

I'd like to move a view from a scrollview to a uiview.
I'm having trouble changing it's center(or frame) so that it remains in the same position in screen (but in a different view, possibly the superview of scrollview).
How should I convert the view's center/frame?
Thank you.
EDIT:
CGPoint oldCenter = dragView.center;
CGPoint newCenter = [dragView convertPoint: oldCenter toView: self.navigationView.contentView];
dragView.center = newCenter;
[self.navigationView.contentView addSubview: dragView];
I can also use (NSSet*) touches since i'm in touchesBegan:
I was having hard time to make it work but the doc wasn't so clear to me.
You can use convertPoint:toView: method of UIView. It is used to convert a point from one view's coordinate system to another. See Converting Between View Coordinate Systems section of UIView class reference. There are more methods available.
-edit-
You are using the wrong point when calling convertPoint: method. The given point should be in dragView's coordinate system where as dragView.center is in its superview's coordinate system.
Use the following point and it should give you the center of dragView in its own coordinate system.
CGPoint p;
p = CGPointMake(dragView.bounds.size.width * 0.5, dragView.bounds.size.height * 0.5);