How to suppress virtual Keyboard slide-in animation? - objective-c

I've got a problem with creating a modal search view that emulates the behaviour of that of the Weather app. Specifically, there are two animations, that are bothering me and introduce unneeded 0.2 s delays:
When the modal view becomes visible, I give focus to the UISearchDisplayController.searchBar by caling becomeFirstResponder in viewDidAppear. However, the keyboard is not visible, when the modal view has slid in, but needs another 0.2s to slide in after the animation of tehe modal view transition is complete. Moving the call to another callback like viewWillAppear or viewDidLoad did no good, the keyboard won't show up in the first place.
When the user touches cancel, there is another animation taking place, before the delegate's searchDisplayControllerDidEndSearch method is called, expanding the search text field and "melting" away the button. Again, this animation is unneded as the modal view is supposed to transition out when the button is touched.
Additionally, when I dismiss and re-present the same view, not only does the keyboard slide in after the transition, but the cancel button does the same (luckily simultaneously).
I am aware of a similar problem described here: Keyboard Animation Issues When Calling becomeFirstResponder within a Modal View Controller.
However, it seems like the behaviour of the search bar is sligtly differet then that of text field. I could not reproduce the steps described by that author to make the keyboard visible by calling becomeFirstResponder in viewDidLoad.
Regards,
Chris

I think I found your answer. When you add a search bar using the interface builder, you can do it two ways: "Search bar" and "Search bar and Search Display Controller".
I was using the second and was having the very same problem you described. I could only invoke the keyboard (using becomeFirstResponder) on "viewDidAppear". But if you do it adding just the search bar it works. Now I can call becomeFirstResponder on "viewDidLoad" and the keyboard appears together with the view itself.
I means a little more work, but really not much. You have to set your controller to be the delegate of the search bar. I added a list view for the results and made my controller become its delegate and its datasource.

Related

Using tap gesture to dismiss keyboard, rest of screen no longer works

I have a UITableViewController that contains a UISearchBar in one of its cells. Following examples here, I put a addGestureRecognizer in my viewDidLoad to capture taps outside the searchBar and calls resignFirstResponder on the search bar so the keyboard is dismissed.
However, this seems to be trapping all taps, the other items in the tableView no longer respond.
This is odd, because I have the identical code (cut and pasted) in another screen, a UIViewController, and it works fine there. The user can continue clicking on other objects just fine.
Any ideas? I suspect this is a simple view hierarchy issue?
Ahhh, it seems the first version I wrote shouldn't work either. The key is to enable the tab gesture only when the searchBar is entered, and then disable it again when you exit. This question has all the code:
Cancel out of UISearchBar when user taps on view

Why isn't my navigation bar controller handling the touchesEnded event on my navigation bar view?

This question came closest to describing my problem, but I'm missing something in the general process and the answer eventually goes into "Never mind, I figured out a different solution that isn't described".
In my case, I've got an XIB with a navigation bar and its controller. For the class fields, I've filled in my custom class names. Here's a screenshot showing the XIB, because I think this should be a relatively simple and straightforward setup...
What I want (like in link at the beginning) is for the touchesEnded event to fire so that I can do something. This works for the "view"; I can programmatically write in the event, set a breakpoint, and see that breakpoint get hit. However, my higher-level goal is to push a new view onto the app at that point -- something that I shouldn't do in the view's functionality, and which I can't do anyway because my view doesn't have access to the navigation controller (unless I do some trickery to retrieve the controller, but I want to do this cleanly).
Even though it works programmatically for the view, the touchesEnded event does not get hit for the navigation view's controller. I set it to the delegate, as shown in the image below, which I'm suspecting is perhaps only a part of what I need to do.
So now that I've set the delegate, and have seen that the touchesEnded event is being hit by the view, why isn't my navigation bar view controller picking up on the touchesEnded event? Am I mistaken and should instead be figuring out how to push a new view from the navigation bar's view, since I've seen that THAT touchesEnded event is being hit? It just seems like something I should be handling in the navigation bar view's controller, but I can't get that controller's touchesEnded event hit.
Thanks!
It's not clear from your post, but it looks like you're adding a navigation bar to your app explicitly, is that true? If your controller is embedded in a navigation controller, then there's no need to do that. You can add a view to the navigation bar, and add a UIImage view as a subview. If you set user interaction to be on, and add a tap gesture recognizer to the image view, you should be able to get the effect you want.
Then you have to override UINavigationBar, and override becomeFirstResponder, returning YES.

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.

UISearchDisplayController not displaying keyboard when text area touched

I have a UITableView in a controller that is nested under a UITabBar.
The interaction is all wired up in Interface Builder so far, nothing done programmatically in terms of view switching.
I've added a UISearchDisplayController as the header of my UITableView. It displays fine, and when I tap on the text entry area, the cancel button appears and the black overlay flies in.
However, the keyboard never appears and when tapping the cancel button, the overlay flies out and the cancel button disappears, but the text entry area keeps focus and the caret stays flashing there, so I cannot tap there again to re-display the search results.
So essentially I have two problems:
Keyboard not appearing when starting to edit text on UISearchBar from UISearchDisplayController
UISearchBar not loosing focus when cancel button is tapped.
What am I doing wrong?
The .xib file that had my tab bar in it contained a UIWindow.
This lead to all sorts of craziness and in the end I gave up on trying to do this with interface builder, and resorted to constructing the UITabBar in code, thereby not creating a second UIWindow.
This resolved the problems and the UISearchDisplayController behaved correctly.
check this method in UISearchBarDelegate:
- (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar;
Try to see if this is getting called and do keyboard-related removal in here. If not, try making another UISearchDisplayController. (I actually never use the default viewController's one). Also, make sure the delegate is correctly set.

Dismiss a number pad-style keyboard without adding Done key

There is no Done button on a Number Pad-type keyboard. I don't want to add a custom Done button, but how do I dismiss the keyboard?
You could add a UINavigationBar/UIToolBar with a done button(a UIBarButtonItem), and make the textField/textView resignFirstResponder on the done button's action.
You can add the UINavigationBar/UIToolBar as inputAccessoryView of textField/textView.
textField.inputAccessoryView = aNavBarWithDoneButton;
Edit: Availability iOS (3.2 and later)
The simplest solution is to add a new button somewhere in your UI that calls resignFirstResponder on your UITextField (or whatever) when tapped. Putting this in a toolbar is problematic on iPhone because toolbars are typically at the bottom of the screen and obscured by the keyboard.
A slightly more complex solution is to put an invisible UIView behind all of your other tappable UI elements. Any taps not handled by your existing UI will go to this new view, which can call resignFirstResponder on your text field.
If neither of these sound appealing, perhaps you should expand your question to include the type of behavior you want.