How do get an NSView from a given location - objective-c

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.

Related

how to find a object in rect or at point

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.

Set a subview as the responder to calls to a parent UIView subclass

I've got a UIView that I've subclassed to be the main view used throughout my app. In it, I have two subviews: banner and container. Banner is basically a place to put an ad or a disclaimer or whatever. Container is meant to act as the primary view, to which you can add, remove and whatever as if it were the only view.
Right now, I'm just overriding the methods of the parent view and sending the calls to the container view. I'm wondering if there is an easier way to do this, without having to write out stuff like this for every method:
- (void)addSubview:(UIView*)view {
[container addSubview:view];
}
Maybe something that lets you delegate all method calls to the view to a specific subview, rather than responding to the method calls itself.
Anyone know if this is possible?
I'm a little confused by the question.
The responder chain is present and passes ui events up through all visible views on screen, by hierarchy. It may be useful to read a little about the responder chain, because by design it passes events from the deepest view to the highest (root) in that order, which is the opposite of the direction you're seeking (if I'm reading this right).
If you need to forward events from a superview to a subview, to respect principles of encapsulation, you should define appropriate actions in your subview's subclass interface, and then then configure your superview to target the actions in that subview/class.

CGContext is being covered by a UIView

I'm not that great with Core Graphics, but I am drawing text on the screen to my CGContext. I am doing this immediately after I add a standard, opaque UIView to my user interface.
Does anyone know why the text I draw after I add my UIView is still at the "bottom" of the user interface?
Thanks in advance.
iOS, like OS X, uses a compositing window manager. Adding and removing UIViews sets their position in the view hierarchy; when and how they're drawn is managed separately. There is no guaranteed relation between when a view is added and when it'll be drawn, and no reason to guarantee one. The content of a view is cached and composited as required from that copy.
If you want to do custom drawing, create a custom UIView subclass, add it to the hierarchy according to where you want it to appear and do your drawing in drawRect: or one of the other override points if you want to render off thread.

Flip coordinate system of an NSWindow objective-c / cocoa

How can I flip the coordinate system of an NSWindow? I know it has a Content View, but how can I flip the coordinate system of that specific View which is of type NSView?
In a sub-view of my NSWindow's Content View I flip the coordinate system by subclassing NSView, placing that in my window, and in that subclassed NSView I implement method isFlipped to return YES. No idea how I could have NSWindow make it's content view out of "MyFlippedSubclassedNSView"
You can't change the internal co-ordinate system of an NSWindow. The closest you can get is to have a flipped view as the content view.
Chances are you don't actually need a flipped content view or window, though. What are you actually trying to accomplish by flipping the co-ordinate system?
No idea how I could have NSWindow make it's content view out of "MyFlippedSubclassedNSView"
Do that. Make a MyFlippedSubclassedNSView instance, and set it as the content view.
Even easier is to do it in IB: Select the window's content view, hit ⌘6 (Identity), and set the view's class to MyFlippedSubclassedNSView.
Looks like you want -[NSView setBoundsOrigin:].

Subviews counted in root CALayer's sublayers?

I noticed today, when adding 1 CALayer and 2 subviews to my view, when I run the following code in my UIView instance:
[self.layer.sublayers count]
This returns 3. Does this mean that a subview is also considered a sublayer? If I only wanted the CALayers that I've drawn in my sublayers call, how would i do that?
Yes, each UIView has an underlying CALayer which is added to its superview's layer when the view is added to the superview.
I don't know the ideal way to find only your own layers. Since sublayers is an NSArray (as opposed to an NSSet), it means it's an ordered list, which means you can be sure that the order in which you add views to the superview is the same order they will appear in said array.
Thus, if you add your UIViews first, and then add your own drawn CALayers afterwards, you can probably get your own by accessing the objects starting at index 2 (skipping 0 and 1) in sublayers.
Of course, if you then add or remove views to the superview you'd have to modify this value, so presuming this actually works, you'll want to somehow dynamically generate it.
You can ascertain the index for a layer as you add it, using indexOfObject: on the sublayers property. A safer route might be to simply store this index somewhere in a list and to access the sublayers with indices from that list only.
If I only wanted the CALayers that I've drawn in my sublayers call,
how would i do that?
You can do this by making the view that is currently a subview of self into a sibling view by having them both be subviews on a containing view. Then your current self.layer.sublayers would just contain the CALayers you added manually.
One way to think about it is that it is the layer hierarchy, not the view hierarchy which defines the render hierarchy. The view hierarchy is just a wrapper to handle interactivity that UIView adds to its underlying CALayer graphics. Thus, when you add a subview to a view, it simultaneously, though in some sense independently, adds its layer as a sublayer to the view's layer. You could probably override this functionality in a subclass or category on UIView...
From the CALayer documentation:
delegate
Specifies the receiver’s delegate object.
#property(assign) id delegate
Discussion
In iOS, if the layer is associated with a UIView object, this property must be set to the view that owns the layer.
Availability
Available in OS X v10.5 and later.
Related Sample Code