I am trying to check for a collision of an UIView that is in the main view, with a UILabel that is a subview of another view in the main view.
When I use CGRectContainsPoint, it does not return true. When I check the UILabel's frame, it returns values relative to the subview it's in, not it's absolute position. I figured this might be the problem.
If so, how do I specify that I want UILabel's absolute values for the frame?
You can convert coordinates between different coordinate systems using the NSView methods:
- convertRect:(NSRect) fromView:(NSView)
- convertRect:(NSRect) toView:(NSView)
If the second argument is nil, the coordinates are converted from/to window base coordinates. Similar methods exist for NSPoint and NSSize variables. One solution would be to convert all rectangles and points to window base coordinates and check for collision in those coordinates.
Related
Given a screen position (e.g. during a drag operation) how would I find the view that's at that position in my application?
Converting the coordinates to window or source view coordinates is simple, but I can't find any routine to get a view from the given location. Is there any other solution than enumerating through all child views/windows recursively?
Please take this a bit further than just NSView's hitTest: message (which is a good answer). Is there a generic message to get the deepest view at a given position regardless of nested window hierarchies (without manually iterating all windows)?
You can use NSView's hitTest: method:
Returns the farthest descendant of the receiver in the view hierarchy
(including itself) that contains a specified point, or nil if that
point lies completely outside the receiver.
[[window contentView] hitTest:aPoint]
But the aPoint has to be in the superview's coordinate system:
Parameters
aPoint
A point that is in the coordinate system of the
receiver’s superview, not of the receiver itself.
You'll want to call -[NSView hitTest:] and it will return the view, if any, containing the point in question. The receiving view should be your root view (such as the NSWindow's contentView) and the point should be converted to that view's superview's coordinates.
First of all you should rarely need it. The concept of "finding a view for an user interaction" is the responder chain. So, if a subview should respond to drag operation, simply add drag & drop capability to that view(s).
If you simply need the deepest hit on a view for that coordinate you can use -hitTest (NSView). Going up to your root view, you will find the parent views. If you have overlapping views, it becomes more complex. Please add that information to your question.
I am writing a small iPad application that draws a shape from a list of coordinates. I would like to tap anywhere inside the shape and have some action occur (i.e. NSLog proving it worked).
Does anyone know how to create a tappable area that is defined by a list of coordinates?
The shape is being drawn on top of a MKMapView.
My approach would be:
Have the points that demark the shape live within a subclass of UIView. Override pointInside:withEvent: for that class. Then look at How can I determine whether a 2D Point is within a Polygon? and use your new knowledge to implement pointInside:withEvent:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
//Left as homework
}
You can use a regular tap gesture recognizer with this :)
Only instances of UIView are tappable, and their area is defined by their rectangular property frame. In principle it would be possible (for very simple and specific shapes) to approximate the area defined by coordinates by multiple UIViews, but this is probably not what you want.
I am new to cocoa /objective-C coming from Java/C# and C/C++ . Cocoa has been giving me lots of headaches. I have read an apple's article on View hierarchy in cocoa. But still confusions.
I need to know when I add a subView to a view programatically not via interface builder. Where exactly will the view be placed relative to other subviews assuming there are other subviews in the same parent view.
In java there are layout managers, in C# there is also vertical/horizontal panel etc, so we know if I add an item/control it will be going to the right of the existing item or to the bottom of it.
So if I do as shown in the following line what exactly determines where the new subview will be placed ??
[[window contentView] addSubview:newView];
Thanks,
The frame of the view defines the rect that it occupies in its superview's coordinates, so its position will be frame.origin. That can be set either before or after you add the subview.
This is spelled out fairly clearly in the View Programming Guide.
It depends on whether you are using Autolayout or not.
If you are not, then when you create a view you call -[NSView initWithFrame:(NSRect)frame] and that frame will will define where the view appears in the superview's coordinates.
_view = [[NSTextField alloc] initWithFrame:NSMakeRect (50, 50, 100, 50)];
will make an NSTextField size 100x50 and it will be placed 50,50 pixels inside the superview.
If you are using Autolayout, then the position of a view depend entirely on what layout constraints apply to it. With Autolayout any frame that you set will be ignored. While autolayout has a steep learning curve, once you set your constraints, it (in theory) means you can ignore the layout.
The frame rectangle gives the view's size and position in the superview. The frame is at position 0,0 (x,y) with a size of 0,0 (w,h) by default. The position in the subview collection is entirely ignored except in rare cases like NSSplitView.
Cocoa doesn't automatically align any views. There is no initial layout mechanism like in .net or java.
You have to position all your views manually by setting their frames in points.
By default, the origin of a fresh initialized view is at (0,0).
AFAIK, the documentation and header file don't specify exactly the origin (x,y) the added subview will be placed. What I do after add a subview is to calculate a new origin (and if applicable) size before repositioning the subview using CGRectMake().
On a NSView there are many other NSViews and some of them are moving with keyboard scroll keys. when moving object come on top of any static one i want to get which object sits under moving one. with mouse this is easy however without mouse i couldn't find a way to achieve this.
You'll need to loop through all of the views you want to test, get each view's frame, convert that rectangle to the relevant view's coordinate system (search for “convertRect:” in the NSView docs), and then use the geometry functions to test whether the moving view's converted frame intersects the static view's frame.
This might help you
-(void)handleTap:(UIGestureRecognizer *)gesture
{
CGPoint tappedPoint = [gesture locationInView:self.view];
NSLog("You tapped in on screen point : %#",tappedPoint);
}
Using this tappedPoint we can check that in which view's rect these points are present.
Important We have to add tap gesture in our view to use this function.
Not even sure how to ask this. Transpose local coordinates to global?
The UIView class has a handful of methods for converting coordinates of CGPoints or CGRects from one view to another. Take a look at convertPoint:toView:, convertPoint:fromView:, etc in the UIView class reference.
You can convert coordinates from one view to another or from any view to the window or vice versa.