delaysContentTouches only on specific elements without subclassing? - objective-c

I have a simple question. In my app, I have a some buttons for navigation inside a UIScrollView, which scroll with the content. This way, when the user enters a text field and the keyboard pops up, the buttons will scroll away for extra space. However, the buttons don't highlight immediately when I tap on them. I've learned that I can eliminate this problem by setting delaysContentTouches to NO, but this makes scrolling nearly impossible, because all the UITextFields and buttons in the view also highlight immediately, stealing the scroll.
I have found a way to only not delay the buttons via a UIScrollView subclass, so this is an option, but I was wondering if there is another way. I generally hate subclassing when it is to fix just one little thing.

The touchesShouldBegin:withEvent:inContentView: method of UIScrollView is intended to be overridden by subclasses if delaysContentTouches is set to YES. So this is the case when subclassing is completely OK.

Related

UIbutton not responding to touch

I have this view hierarchy:
The three buttons don't response. They are enabled, just when I touch there, they don't do anything (not even change their gradient/tint) which tells me they are not even received the touches. Is there something I am doing wrong?
Thanks
User interaction is enabled on all the buttons' superviews, and the buttons themselves. The buttons are also enabled.
Are you using any imageViews on top or containing the UIButtons? If so, sometimes, those absorb the touches because they have the userInteraction boolean set to NO by default. Maybe even getting rid of your gradient imageView (for the time being) to determine if those are causing the issues.
If not, I would set a breakpoint on the viewDidLoad method of the superview and type in [self.view recursiveDescription]. It should give you at-a-glance overview of what's around those buttons and might be stealing the touches.
Good luck!

Handle tap event by subview of UIScrollView while scrolling

I have custom UIScrollView subclass with some content views inside. In some of them I have UITapGestureRecogniser. All works fine when scroll view is not scrolling. But when it scrolling content views does not receive tap action. What is the simplest solution to handle tap action by subview while scroll view is scrolling?
Details:
MyScrollView scrolls horizontally. It contains a lot of content views (e.g. MyContentView). Each MyContentView has width about one third of MyScrollView width. So there are about 3-4 visible MyContentView elements at a moment. The main behavior of MyScrollView is to 1)make sure that after scrolling one of MyContentView elements will be at center of screen and 2)to scroll to center of MyContentView if user taps on it. So the main answer I hope to get is how to "properly" implement handling of tap action in MyContentView while MyScrollView is decelerating.
I found some same questions and answers but none of them satisfied me. The best was to implement gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: of UITapGestureRecogniser delegate. But in this case I sometimes (when I tap, make smaaaal drag and release finger so tap is steel recognizable(lets called it quasi tap)) have both tap and scroll events and it leads to bugs for me even if scroll view is not scrolling when I begin tap. When user make quasi tap my application tries to scroll to tapped MyContentView element and than immediately handle normal scrolling. It seems even more terrible, due to some other functionality start to perform after handling tap (it must not perform when normal scrolling).
I need solution where scroll view wait enough to decide it is not tap event and only then make scroll. Otherwise if tap event had recognized scroll must not happen.
You can go with the custom delegates methods as well, using #protocol. Implement those delegate methods in view controller where your UIScrollView has been added.
like in MyContentView:
In touchesBegan method,
[self.delegate contentViewTapped:self];
Now in ContainerView class where scroll view is added, implement that method:
- (void)contentViewTapped:(MyContentView *)myContentView {
NSLog (#"ContentView no: %d", myContentView.tag); // if tag has been set while adding this view to scrollview.
}
Go through the examples for #protocol.
Hope this is what you required.
Enjoy Coding :)
This is built into UIScrollView - take a look at the delaysContentTouches and canCancelContentTouches properties. This should alleviate the problem when dragging a small bit after a tap.
This is all system built-in behaviour. I would suggest sticking with what Apple has provided for the feel of your interface (how it reacts to small drags, for instance) so that your app doesn't feel out of place on a user's phone.
EDIT:
Alternatively, you could disable scrolling of your scroll view in you gesture recognizer and re-enable it once it's ended/cancelled.
Further Edit:
I don't understand - I've created a sample project that illustrates how to intercept touches in a subview of a scroll view using gesture recognizer delegate methods. Play close attention to the "Cancellable Content Touches" and "Delays Content Touches" properties of the scroll view. They're both YES for very important reasons.
You scroll view should be delaying content touches until it has determined if the user is attempting a tap, pseudo-tap (as you put it), or a pan for the scroll view. Apple has already written the functionality you're trying to build; UIScrollView will already do what you want.
The problem is that the system doesn't want a scroll view's subviews intercepting tap events while the scroll view is scrolling. To this end, it cancels touch events if it determines that the user is actually trying to pan. Setting "Delays Content Touches" enables this behaviour. Ensure it's turned on and you should be fine.

Setting tab order for NSTextFields of an NSView

I am trying to set the tab order for NSTextFields on a given NSView. As far as I understand it I have to connect the NSTextFields with InterfaceBuilder by setting the nextKeyView outlet to the next NSTextField. I did this - and there is no effect. When I press tab, after being in one of the NSTextFields it just loses focus and that is it. No matter how often I press tab none of the other NSTextFields regain focus.
I also read that I need to set the initialFirstResponder of the window. I don't think I can do this in this particular case, because my AppDelegate calls up a NSView which in turn acts as a Menu-Area with many different buttons, which each call up different NSViews that are loaded as subviews of a different view. Therefore the AppDelegate has no way of knowing which NSView is currently loaded.
Is there a way to set the tab-order of NSTextFields on an NSView-basis?
Thanks
You have to disable auto-recalculation of the key loop in the window. See -[NSWindow setAutorecalculatesKeyViewLoop:].
Edited to add: this can be set in Interface Builder, too.
This may or may not help for your situation, but the following worked for me when dealing with an NSView within another NSView. I had two vertical stacks of NSTextFields. Rather than traversing horizontally, I needed to tab down one stack and then the next... So I embedded each of the two vertical stacks in their own box (In IB, first select your items, Editor> Embed In> box). Works perfect.
If you don't want the look of a box, you can clear its title and set its border type to none: invisible box.

Set NSScrollView to not editable

I was wondering how to take care that my NSScrollView is not editable by the user, but i didn't find a way, there is no option in IB, nor do I find an appropriate method of the NSSCrollView class.
A previous post suggested to implement a delegate method
- (BOOL)textShouldBeginEditing:(NSText *)aTextObject
to return false, but this didn't work for me yet.
No solution was given on the previous question.
(I also tried selecting the TextView everything it doesn't display an option 'editable' i just downloaded the new Xcode so the version shouldn't be a problem)
You can't make NSScrollView non-editable. You can hide scrollers with setHasVerical/HorizontalScroller: that would prevent user from scrolling.
If you have NSTextView and want to make it non-editable just send setEditable:NO to it, not the scroll view. For that you obviously need a reference to the NSTextView or use NSScrollViews -documentView.
what is inside the scrollView that you want to prevent editing of?
what views have you got embedded in the scrollView? you need to find the view embedded in the scrollView that you want to prevent editing on, and call setEditable:NO on it.

Custom Views or Custom Cells

I have a question about creating custom views. I wanted to implement an interface where I want to have different objects configured in one place, each of them with it's own controls. Kind of like in automator, on the right side view where the workflow is shown with different actions. Are those NSView or NSCell subclasses ?
Any example will be appreciated !
Ken
Here's how you can tell an NSCell and an NSView apart:
NSCells are basically stamps. Given a certain value/object, the NSCell knows how to draw that on the screen how you want it. Like NSTextCells know how to draw NSString's on the screen how you want them. NSCells don't have state, don't remember anything, they're just a one-shot set of drawing instructions that get executed with a given value/object. The idea is to reuse NSCells as much as possible to make drawing things on the screen super simple.
NSViews are sort of logical containers for what goes on on your screen. They can technically do their own drawing, but quite a few of them use NSCells to do their drawing. For example, NSTextField uses an NSTextCell to draw it's text on the screen, it also contains the extra logic necessary to toggle between editing and not-editing by displaying the text box you can type in during editing and using the NSTextCell when you're not editing. NSViews are also part of the responder chain and can respond to mouse-clicks, keyboard events, and the sort.
You're probably going to end up with both, NSViews to hold all the controls you want to use to configure each object and NSCells to draw custom UI elements (like if you use non-standard controls).