NSPageController, deactivate swipe gesture - macos

I'm currently using a NSPageController to navigate between a Master and a Detail View in my OSX Application. I'm basically using it only to support transition animations, since there is no NavigationController on OSX.
However, the default NSPageController is listening on swipe gestures from my magic mouse and trackpad and changes the displayed view on a horizontal swipe. (like going back / forward in your browser). I would like to deactivate this behavior but overriding and intercepting any gesture method in a NSPageController subclass had no effect so far.
It seems like a NSScrollView / NSTableView does absorb these touches since doing a horizontal swipe gesture above any of my TableViews won't result in a view transition. (It only absorbs them for my magic mouse, doing a swipe gesture on my trackpad still results in switching views)
Target OS: Mac OSX 10.9 +
Thanks for your help!

You can make a subclass of NSPageController and overwrite
- (void)scrollWheel:(NSEvent *)theEvent
This should help.

Related

Disable Gesture Recognizers in a *subview* so that superview Gesture Recognizers can run

I have an NSView (the canvas), into which I'm dropping a set of TextView subclasses (small boxes). The TextView classes have GestureRecognizers on them for drag drop (move) and select.
The canvas has two modes:
drawing
text
In text mode, I can interact with the TextView classes - I can click on them, edit etc.
When I switch to drawing mode, I want to disable the TextView boxes completely, and have all events/gestures be captured by the Canvas.
That way I can do Pan/Click events on the whole of the canvas, and the TextView boxes should be visible but otherwise ignored/disabled.
To enter drawing mode I disable the TextView boxes as follows (if the boolean "drawing" is true, then I turn off all event handling in the TextView boxes):
foreach (var tv in textBoxes)
{
tv.Editable = !drawing;
tv.Selectable = !drawing;
#if __IOS__
tv.UserInteractionEnabled = !drawing;
#else
tv.AcceptsTouchEvents = !drawing;
#endif
foreach (var g in tv.GestureRecognizers)
g.Enabled = !drawing;
}
So everything works perfectly between the two modes on iOS. On the Mac everything mostly work with one exception: in drawing mode (when the textview and textview gestures are disabled) if I start a gesture on top of the TextView box, nothing happens. Neither the Canvas gesture handler NOR the TextView box gesture handler are called. Starting a gesture anywhere else works fine and the Canvas gesture handler receives it.
In summary, my question is: how can I completely disable gestures in a subview, such that the superview gesture will be recognised, even if the gesture starts on top of the subview.
There are samples of handing a gesture to a subview, but here I want to hand a gesture to a superview (which should be top of the responder chain I thought).
Any advice would be gratefully accepted.
It seems that the solution is to ensure that the subview you want to receive gestures has to be at the top, otherwise gestures dont seem to reach it (this means it has to be the last item in the Subviews array).
In other words, if another subview "A" sits above your subview "B" - and that subview "A" is completely disabled with no gesture recognisers... it will stop any gestures in "B" from being recognised.
Gesture recognisers are not supposed to use the responder chain... (that is made clear in UIGestureRecognizer specs, but not NSGestureRecognizer specs). Here is a quote from the latter:
Events received by your app are forwarded automatically to any
relevant gesture recognizers before they are sent to the corresponding
view
This doesn't talk about how events flow up the responder chain for gesture recognisers on the Mac.
So as mentioned above - bring your subview to the front to ensure its gestures will be recognised. With the Mac, there is no way to easily order subviews of NSView (unlike UIView which has bringToFront, sendToBack etc). So the best way I have found is to use SortSubviews, with an appropriate ordering function.

Using infinite scrolling UICollectionView with iOS 13 pullable modals

I have a modal window, which is perfect for iOS 13's drag to dismiss gesture, because this way the user remains in the context, so I don't want to use full screen. The controller contains a UICollectionView which displays a month calendar, which is scrollable vertically.
The problem is, that when the user wants to scroll upwards in the collection view, the dismiss gesture is triggered instead. If I scroll down first, then can I only scroll up.
I've tried to disable the internal UIPanGestureRecognizer (it seems somehow there is no presentedView, so it didn't work), tried to set the UICollectionView's pan gesture recognizer delegate to prevent the system recognizer to fire (it turned out you can't do that), and tried to scroll the collection view on appearing a bit (ugly).
How can I elegantly convince the the modal presentation, that my scrollview isn't scrolled to the top?

Scrolling NSTextView in OSX Today Widget with scrollwheel

I have the following view hierarchy in Today Widget app:
NSScrollView
NSClipView
NSTextView
When the text in NSTextView is bigger than it's size, I am able to scroll by highlighting text with a mouse, or by using arrow keys.
But when I try to scroll with mouse wheel or trackpad, it does not work. The question is similar to this one: NSTextView does not scroll when created with NSCollectionView, but the NSTextView is now being placed on top of bigger srollview of side panel (where Today widgets are).
I think, it may be related with responder chain. The scrollview of NSTextView does not even get events, such as:
- (void)scrollWheel:(NSEvent *)theEvent or
-(void)mouseEntered:(NSEvent *)theEvent
How can I solve this problem?

UIScrollView on tvOS

The question is very simple, how to enable scroll and zoom inside a UIScrollView in tvOS?
I tried the same initializer code from iOS and returned the scrollview for the focusedView var, but nothing happens when i touch the remote.
Also, i tried to add another custom UIPanGestureRecognizer to the scrollview and actually it works, but i don't want to handle the pan with custom code, just use the same pan behavior like iOS.
Let me know, thanks.
You can configure the scroll view's built-in pan gesture to recognize touches on the Siri Remote. It doesn't do that automatically, because normally scroll views on tvOS aren't scrolled directly by touches: they're scrolled automatically as focus moves between views within the scroll view.
If you really want the scroll view to move directly from touches, you'll need to add UITouchTypeIndirect to the allowedTouchTypes of the scroll view's panGestureRecognizer:
scrollView.panGestureRecognizer.allowedTouchTypes = #[ #(UITouchTypeIndirect) ];
You'll also need to make sure that either the scroll view itself is the focused view, or is a parent of the focused view, since all touches from the remote will start at the center of the focused view: you need to make sure the scroll view is getting hit-tested for the events to work.
Zooming won't work, because the Siri Remote can only recognize one touch at a time, so you can't do a pinch gesture on it.
Swift 4 version (from here: https://stackoverflow.com/a/41000183/945247)
scrollView.panGestureRecognizer.allowedTouchTypes = [NSNumber(value:UITouchType.indirect.rawValue)]

Cocoa - Giving focus to a WebView in an NSStatusItem

I've set the view for my NSStatusItem to a WebView, but I'm not able to capture hover events in the WebView because my NSStatusItem doesn't get focus, like a normal WebView would.
How do I programmatically give my NSStatusItem or its associated view focus so that the embedded WebView will capture mouse events like a normal WebView?
In case anyone cares, one way I can think of is to have the view for the NSStatusItem be a custom NSView that overrides the NSResponder methods mouseEntered:, mouseMoved: and mouseExited:. Then, I would add the WebView as a subview of the custom NSView, and each time the mouse moves inside the NSView, send the coordinates of the mouse to the Javascript in the WebView, which can figure out what element is at the position of the mouse cursor.
Basically, it would be reimplementing mouse hover at its core. Hopefully there's an easier way though.

Resources