NSView loses mouseMoved/mouseDragged if dragged in from subview - objective-c

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.

Related

UIButton steals UIView touch events

I have a class which subclassed UIView. The class only have touch methods (to rotate view according to users touch).
From storyboard i added a view to my ViewController's view and subclassed it with that custom class. The idea behind to receive its touch events, thats it.
In that View some UIButton is place covering the whole view.
Now requirement is when user clicks on button then its action should call else if he tries to rotate the view it should give spin rotation.
Every thing is working fine if i make user interaction of button to be false as obviously now Uiview is the responder. But this not what i want. I want button to be interact to action as usual and if user move his figure then rotate the view.
I achieve same thing with UIRotationGestureRecognizer but it is meant with 2 figures touch and i need to achieve same thing with single finger touch.
Any help and suggestions will be appreciated.

NSEvents pass through NSView when overlapping another

In my custom NSWindow class, I have a Parent view (set as the window's contentView), with a Child. Throughout my application, I have appended subviews to my Child view, which all appear to receive mouseDown responses perfectly. However, I wanted to have a panel slide into place above the Child view (yet still housed within the parent view) upon clicking of a button (I'm calling it slidingOverlay in my application). Upon adding the slidingOverlay subview (which subsequently contains more subviews) to the Child view, I am unable to click any of its elements, as they all pass on through to the lower, Child view.
A couple details:
I have tried overlaying the slidingOverlay as a subview of both the Child view and the Parent view, both resulting in the Child view receiving NSEvents.
The slidingOverlay appears to be non-opaque (translucent? not sure if Apple has a term for it), despite being plainly visible, layer-backed, and having a solid color. Perhaps this is the origin? I'm rather new to Cocoa.
All three views are actually layer-backed (Parent, Child, and slidingOverlay).
All three views were created programmatically.
I have tried overriding (NSView*)hitTest:(NSPoint)aPoint for Child, and forwarding the NSEvent to slidingOverlay's subviews works. However, this method seems kinda hack-like and requires me to predetermine which slidingOverlay subview will receive events. I want all slidingOverlay subviews to be able to get clicks, ignoring all lower subviews, while slidingOverlay is visible.
Just to summarize, there is an NSWindow, with a contentView of Parent. Parent has one Child with subviews (NSButtons, drop downs, custom classes, et cetera), all receiving clicks. The slidingOverlay, in its present state, is appended to Child as a subview (which should work fine according to my grasp on things), and its visibility can be toggled. When toggled on the mouseDown NSEvents to slidingOverlay and its children are being passed to the underlying subviews of Child - for instance, clicking point 100,400 will result in the drop down (direct subview of Child, but underneath the visible slidingOverlay layer) to be expanded.
I guess the question is - when an NSView (with containing subviews) is atop another view, how would it be perceived as "solid" and clickable, in favor of it's parent, or underlying views?
Looks like attaching a new NSWindow (replacing slidingOverlay) works (in favor of further layering Child). Still no idea why NSEvents pierce through after a certain number of subviews are attached, though…
It is related to the placement of subviews in their array.
Whenever subviews are overlapping, the subview that added later will take the mouse event. The zPosition in layer-backed views won't help either.
You can fix this by sorting the subviews using the following method:
- (void)sortSubviewsUsingFunction:context:

Prevent UITableView from scrolling when custom subview is handling touches

In my iOS app have a UITableView which contains a custom subview in one of it's cells. This cell is an interactive view that handles touch events (touchesBegan, touchesEnded, touchesMoved) to update itself.
The problem is that when the user 'drags' up or down, the tableView catches these touches (although I don't pass the touches up the responder chain), scrolls the table and prevents the subview from working correctly. I would like to prevent the table from scrolling as long as the user is touching that particular subview.
The subview has no reference at all to the tableView.
How can I prevent the scrolling behavior of the table?
Update
Despite accepting the answer below, I ended up handling my situation differently. I handle the touch events in my custom view now, pass them up the responder chain (to the table cell), the cell handles the touch events as well, using them to enable/disable scrolling on the superview (the table).
Turning off "Cancellable Content Touches" in the UITableView solved this for me (in the UITableView attributes inspector under Scroll View / Touch). I got this from this SO question: Scrolling a UITableView inside a UIScrollView
From the UIScrollView:canCancelContentTouches doc:
If the value of this property is NO, the scroll view does not scroll
regardless of finger movement once the content view starts tracking.
The most common method I use in such cases is to delegate information up the event chain. Set delegates in manner:
subview->cell->table
The second thing you can do is to send a notification via Notificaion Center. Table would listen to any events that forbid normal scrolling. It is overshoot but it will leave your code consistent.
I have no more ideas at the moment.

NSTableView steals -mouseUp: from mouse drag sequence started inside an NSView sibling

NSView A contains an NSTableView (in an NSScrollView), a child NSView B, and listens to mouse events by implementing -mouseDown/Dragged/Up:. NSView B implements neither of these methods, so the original NSResponder ones should forward the corresponding messages to its next responder (parent view).
When the mouse is clicked inside, dragged from NSView B, and released over any object other than the NSTableView, the whole dragging sequence (down/dragged/up) is sent to the parent view normally.
If, however, the mouse is released over the NSTableView, the -mouseUp: message is never sent to the parent view. Instead, it is stolen by the NSTableView.
This behaviour can be changed to normal by subclassing NSView B and implementing the -mouseUp: message so that it simply passes the event to its next responder (precisely what the original NSResponder method is supposed to do).
Observed on OSX 10.7.4/Xcode 4.4. A test project can be downloaded from here: http://www.filefactory.com/file/41ung2am0aax/n/TestDragging_zip
Is this an expected behaviour or a bug?

How to block NSView events under another NSView?

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.