I have a project with a UIScrollView which I want to control the zooming programmatically but not via user interaction. I have tried setting the multipleTouchedEnabled property to false. This doesn't work. When I pinch on the scroll view, the scrollViewDidZoom and viewForZoomingInScrollView are called. I have also tried subclassing UIScrollView and overriding addGestureRecognizer and disabling the gesture which passes a [gesture [isKindOfClass: [UIPinchGestureRecognizer class]]. After breakpointing on that override, no gestures are matched.
So how can I have zooming on the scroll view but not allow manual interaction with the zooming. I still need single finger panning for normal scrolling.
Try to set scrollView.pinchGestureRecognizer.enabled = NO;
Related
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.
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?
I need to disable programmatically scrolling in NSSrollView with enabled responsive scrolling.
I try override isCompatibleWithResponsiveScrolling, then is possible to override scrollWheel and have enabled responsive scrolling but scrollWheel works different in that implementation. Is called only once, on start of scroll but I want to break scroll that is in progress.
It's possible to do this in different way that not need to override scrollWheel method?
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)]
I've created a custom scroller for my textview (initiating it in the awakeFromNib method of the scrollview) and now I want to let the user chose if he wants to show the scrollbar on application startup. The problem is that the scroller always appears even if I hide it immediately after I created it and set it to be the scroller of the scrollview. The weird thing is that trying to hide the scroller after an event has been triggered (for example by clicking on a checkbox in the preferences) the scroller properly hides and shows. What I'm I doing wrong? Any help is appreciated!
The weird thing is that before adding the custom scroller to the scrollview I have to use setHasVerticalScroller:YES, otherwise I can't scroll using the two-fingers scroll gesture. Then, if the user doesn't want the scrollbar to be shown I have to use setHasVerticalScroller:NO in the document's windowControllerDidLoadNib method, using it just after having added the scrollbar in the scrollview's awakeFromNib method won't work. Well, at least now it seems to work!
I've always used IB to set up scrollbars and then used the following line if I want to suppress one of them:
[self.aScrollView setHasHorizontalScroller:NO]; // so only the vertical scrollbar is active
Try using that line in awakeFromNib, later setting it to YES if user chooses, rather than using the "hidden" property.
P.S. An NSTextView added in IB is always embedded in an NSScrollView, and it's the scrollview that governs the scrollbars. So if the above doesn't work, try calling setHasWhateverScroller on the superview of your textview:
[[[aTextView superview] superview] setHasHorizontalScroller:NO];
If you get an "unrecognized selector" error, then try explicitly casting the superview to NSScrollView (which will work only if the superview really is an instance of NSScrollView):
[(NSScrollView *)[[aTextView superview] superview] setHasHorizontalScroller:NO];