How to block NSView events under another NSView? - objective-c

Here is the idea:
I have a NSWindow containing 2 NSView, let's call them ViewA and ViewB.
ViewA has a list of subview objects, each object has its own tracking area set and handles a mouseDown event. ViewB is a hidden view, which appears above ViewA.
The problem is when ViewB appears, ViewA still receives mouseDown events. So when I click on ViewB, the object behind the ViewB receives the mouseDown event. I would like to know if there's any way to block the events of ViewA while ViewB is over it.
I know I can remove the tracking area from every object, but it still responds to the mouseDown event.

You can override sendEvent: method on NSWindow and test 'firstResponder', if it is ViewA, than not call [super sendEvent:event] so ViewA will not receive any event.

If view B is a subview of A, the problem is that it's hidden. Don't hide it: just set its opacity to 0. That way you won't see it, but the responder chain will.

In case anyone still looking for answer for these kind of questions nowadays, I only managed to do this with a child window, solution described in this accepted answer. Also, if you want to make the window transparent (/clear colored), but still receive mouse events on it, put this line into action as well:
[overlayWindow setIgnoresMouseEvents:NO];

Sibling views block, descendant views dont as the child will propegate mouse events upstream to its parent. To block descendants propegating events to their parent you must overide the event in the child and not call super on the same event. Calling super will propegate the event to its parent. Here is a full explination on Events and hittesting sibling/descending views: (be warned its dense) http://stylekit.org/blog/2016/01/28/Hit-testing-sub-views/

you can also disable the touch events for ViewA by [ViewA setAcceptsTouchEvents:NO];
and can enable them again as per your requirement by setting YES again.

Related

NSView doesn’t catch keyDown events

I need to catch mouseDown and keyDown events in a subclass of NSViewController and as it’s not possible (please, correct me if I’m wrong) I left my GameViewController class blank and put all it’s methods to a new GameView class. In the identity inspector of GameViewController.xib I set my class to GameView while File’s Owner is set to GameViewController. After all, my mouseDown method works, but keyDown doesn’t.
I tried this:
- (BOOL) acceptsFirstResponder {
return YES;
}
but it didn’t help.
Please, show me what to do.
UPD: Actually keyDown method works, but first I need to click somewhere on the blank space of my window and only then everything works as it was planned. Once again, mouseDown events are triggered with no problems. What may I be doing wrong?
Your view accepts first responder when offered it, but nothing is attempting to make it the first responder until you click.
Set the window's initialFirstResponder some time before showing it. If you're using a NIB, it can be set there. Or you could do it programmatically.
After the window is shown, you can call [window makeFirstResponder:view] to make the view the first responder of its window.

Track if there is a mousedown/up in a subview from a NSPopover

Here is my current object hierarchy:
A view has a button that opens an NSPopover, which contains another view (An NSControl)
I am listening for a mouseup event on my NSPopover, at which point I close my NSPopover.
However, I don't want it to close if I'm in the NSControl (i.e, if there was a mousedown/mouseup event in the NSControl)
So my plan is to identify when a mouseup/down event is found on the control, then ignore the NSPopover closing on my mouseup event listener in the NSPopover
Has anybody done anything like this before? Any ideas?
Thanks in advance!
My solution ended up being tracking if the popover is open in the root view controller, and if the root view got a mouseup event, and the popover was open, I could break out of the code

NSView loses mouseMoved/mouseDragged if dragged in from subview

A = the parent NSView;
B = the child NSView;
B has a small NSTrackingArea;
B is a small subview of A;
A correctly receives mouseMoved and mouseDragged events if moved,clicked, dragged in a empty area.
If i click in B and drag the mouse outside of its bounds into A, A does not receive any mouseMoved or mouseDragged events.
Can someone point me to what i could do to get the superview A to react to this drag?
I've observed this and I was able to solve it by doing as follows:
Create a NSViewController and set viewA as its "view" property.
In my case, I implemented mouseDragged in the view-controller but
you can try on the view and see what results you get. mouseEntered
and mouseExited were implemented in the view subclass.
Tip: Make sure you're updating the tracking area bounds as needed.
Hope this helps.

Show UIAlertView in viewDidDisappear: buttons not reacting?

In viewDidDisappear: of a modally presented controller I added a callback to inform who ever is interested about the view being gone (after the animation has finished) without requiring subclassing.
One of my controllers that registered for the callback is firing up a UIAlertView in there. However, once the alert is shown, its buttons don't react.
Another one is adding a subview to itself and again: the buttons of the view don't react.
The resposible handlers of the buttons are not triggered.
I assume it has to do with the fact that viewDidDisappear: is not really finished yet when it call my callback. But even if I used subclassing instead, it would be the same situation.
One explanation could be that there is still some other view covering my buttons because the clicks just don't come through.
So: Can somebody confirm that it is NOT a good idea to do what I am doing (showing an alert, adding a subview in viewDidDisappear), because then I will have to change the flow. If it should be okay, I have to figure out what else is causing this effect.
I'd put the callback into viewWillDisappear: instead. At least then the original UIView reference is still around.
Better solution would be to dismiss the modal view through the parent controller by adding the caller as a delegate. The delegate would implement a protocol to dismiss the modal controller. Call the delegate protocol from the modal view, when you are ready to dismiss.
To avoid changing the flow, you could schedule a timer to show the alert, this will give a chance to the view controller code to complete

Calling another view from within a view class

i may be making more out of this because of the late hour. i am confused. i have multiple views i call from a viewcontroller class. typically they are called with a uibutton object. say i have two views. main and child view. here is how i would call the child while the main view is visible.
[self presentModalViewController:childViewController animated:YES];
now because i want to use touch events to call the child view i believe i am forced to initiate the events from with the main view's class.
so how do i call the child view from within the main view class as i would when i am in the view controller class.
thanks for any help!!
If I understand you correctly, you're wondering if you need to handle touches in the main view itself, rather than in the main view controller. If that is correct, the answer is no, you don't have to.
The way events work in Cocoa is that they propagate up through a chain of objects called the responder chain. The last/lowest object in the chain is given a chance to respond to the events first. In this case, that object is your "main view". If the object can not respond to the event, the event goes to the next object in the chain, what's called the object's next responder. This progresses up the chain until an object responds to the event.
The reason you don't have to worry about this is that a UIView's next responder is its view controller. This means that if you don't handle the event in your view, it propagates up to the view's controller (and, if you don't handle it there either, it continues up the responder chain). So, if you implement the -touchesBegan:withEvent:, -touchesMoved:withEvent, and the other event-based methods in your view controller and not in your view, you'll be fine.
For further reading on event handling in Cocoa, see this section of the iPhone Application Programming Guide.