iPhone: dismiss keyboard when user touches background - iphone

I have read some other articles like here and here but unfortunately there are some differences in my code that won't make these work (so please don't suggest these answers).
I would like to dismiss the keyboard when the user taps the background. Normally this would be easy, except that my UITextField objects are inside a UIScrollView which makes it so I can't catch the touch events (the UIScrollView swallows them so they don't reach the base view). One way to get around this is to register for a generic gesture (a tap), but this catches all taps, including the ones intended for the submit button.
So basically, 'touchesBegan:withEvent:' wont work because it never gets called, and gestures wont work because they dont account for button presses.
Here's the question: is there some way to detect a simple tap on a UIScrollView? Once I detect the tap I know how to do the rest. Thanks!

You can't use touchesBegan:withEvent on the superview of the scrollview, but what about subclassing UIScrollView and handling the touch there? You can then proceed normally with a call to super's implementation to keep from stepping on the UIScrollView's toes:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Insert code to dismiss keyboard if needed */
// This makes sure scrolling proceeds normally.
[super touchesBegain:touches withEvent:event];
}

I also ran into same problem. While in IOS 6.0, it was working fine, but as soon i switched to IOS 5.0, it started to show the same behaviour you have mentioned.
Workout for IOS 5.0 - You should use the UITapGestureRecognizer. Then set its delegate to self and implement the following delegate method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
as
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return ! ([touch.view isKindOfClass:[UIControl class]]);
}
#end
above code will verify that the object under touch is not a UIButton or any control element, then only handle the touch
I hope it would solve your problem.

Related

touchesBegan doesn't respond

I'd like to use the touchesBegan method to know when the user is taping somewhen outside of a UITextField in my TableView.
I've got a UIView that contains a TableView, and I have the following method :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"See a tap gesture");
UITouch *touch = [touches anyObject];
if(touch.phase==UITouchPhaseBegan){
//find first response view
for (UIView *view in [self.view subviews]) {
if ([view isFirstResponder]) {
[view resignFirstResponder];
break;
}
}
}
[super touchesBegan:touches withEvent:event];
}
My self.view and my self.tableView have both the userInteractionEnabled set to YES, but for some reason, touchesBegan is never triggered. Any idea?
If your UIView contains your UITableView, then the table view is at the top of the responder chain and the touch events won't make it into your view. But there might be a better way to do this. What are you after?
UPDATE
Implement UITextFieldDeletate's textFieldShouldReturn: method to intercept a press of 'Return':
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
Also, a UITableViewDelegate is a UIScrollViewDelegate, so you can hook into those methods to determine when the user interacts with the table view.
Generally speaking I think you don't have to worry about dismissing the keyboard immediately when a user touches outside of it, especially if you have other text inputs on the same screen.
MOAR
Ok, fair enough, but things start to get complex when you intercept touch events via composite transparent views (these can get expensive as well), and so on. And you never know the repercussions that will arise down the road, not only for the user but for you the programmer when you want to upgrade the app in the future.
Why not keep it simple? How about just a 'Done' UIBarButtonItem, or a little translucent UIToolbar that slides up on top of the keyboard/picker ala Mobile Safari? These solutions are acceptable to the user, and can wind up making his life easier. They certainly make development easier by separating artifacts and functionality into modular units.
One final note
Using UITapGestureRecognizer I think will be difficult to get right in your situation. I'm worried that any tap recognizer you add to the table view will prevent things like row selection or moving control to another UI element (text field, switch, etc).
Try adding a tap gesture recognizer to your table view. That way you should be able to allow the normal behavior as well as capturing the tap event to do your extra stuff.
I've implemented similar functionality in one of my applications, I did use textFields rather than textViews, but it should still work. I used
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[textField reresignFirstResponder];
}
Without doing any checks, if the user taps the resignFirstResponder method gets called, but if the user taps on the textView, then that triggers it to become the first responder again, resulting in no visible change. I've implemented this concept on an app with 9 textFields on a single view, and I have yet to experience problems.
Make sure you have set your object to process those touch events:
[myButton addTarget:self action:#selector(buttonTouch:withEvent:) forControlEvents:UIControlEventTouchUpInside];
And then process the touch event in the method you declared:
- (IBAction) buttonTouch:(id) sender withEvent:(UIEvent *) event
Updated for UIView (Assuming you already have an outlet created and wired up):
[myView addTarget:self action:#selector(myTouchEvent:withEvent:) forControlEvents:UIControlEventTouchUpInside];
And then:
- (IBAction) myTouchEvent:(id) sender withEvent:(UIEvent *) event
Now that I understand what you are trying to do (dismiss the keyboard when touching outside the textbox), there is a simple solution that works well with almost every scenario).
Step 1 - Create a button that is sized the same as the View that the TableViewController is placed in. (large button).
Step 2 - Send that button to the back (Editor->Arrange->Send to Back)
Step 3 - Wire up an IBAction to that button and call it dismissKeyboardButtonPressed (hint if you are not already using the assistant editor, you should be)
Step 4 - Inside the IBAction method put (assuming your TextField is called myTextField):
[myTextField resignFirstResponder];
Step 5 - Run it. Whenever you touch anywhere in the view outside of the textbox, it will dismiss the keyboard.
This is the method I use almost anytime I put a TextField on a view, and need to dismiss the KB when touching outside the TextField.

How to freeze UI when start up?

When the app is launched, I want to freeze UI for a second or so to get a precondition service (for example - location service) initialized. Is there a way to do that?
Just place a transparent UIView on top of the entire screen and have it intercept all touch events.
To intercept touch events, simply subclass a UIView and override
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
Usually inside that method you'd call super on it, but in this case you would just return YES:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return YES;
}
If you'd like to be really fancy you can add a synthesized property to the UIView subclass called shouldInterceptTouches and do something like this:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return shouldInterceptTouches ? YES : [super pointInside:point withEvent:event];
}
Also remember to make sure that your transparent view is above the other views.
Side-note: Apple's Human Interface Guidelines don't like it when you do stuff like that. A user will be confused and disappointed if your app is not responsive and it may cause them to quit the app if they think it's frozen. You're better off displaying some sort of UIActivityIndicatorView and disabling only the buttons absolutely necessary. Apple likes it when you do stuff like that in the background and allow the user to do other things, just in case it takes a while or fails.
You could use a Modal View or disable all components until the location service has finished.
This is the responsibility of the application not the OS or the frameworks.

UIGestureRecognizer not consuming taps

I have a UIViewController and I am adding subviews to the main view. The main view has a UIGestureRecogniser and each subview also has a UIGestureRecognizer. In interface builder I have checked canceled in view in the attributes inspector so I would expect taps on the subviews to only fire my gestureRecognizerShouldBegin in the subview handler but they are also firing the handler attached to the view they are place on.
Does anyone have any idea why this might be the case?
I guess I could keep a handle to the particular instance of the GestureRecogniser attached to each subview and compare if the event being fired has come from the correct recogniser but this does not seem like the correct solution. Any help would be much appricated.
Edit: This second solution doesn't even work seems like every UIGestureRecogniser conforming to the current gesture is being fired!
Edit:
The best solution I have come up with is,
(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if([view isEqual:[touch view]] && self.editing)
return YES;
return NO;
}
I would like the Gesture not to receive the touch at all though

Tapping a UIScrollView to hide the keyboard?

I'm working on an iPhone app which involves typing stuff into a UITextView, which adds content to a UITableView. The problem is, I need to be able to close the keyboard when the user's done with it, and the only area that is really visible other than the keyboard and UITextView at this point is the UITableView. I'm having trouble implementing a touch event on the UITableView (as in, touching the UITableView anywhere, not just didSelectRowAtIndexPath:). Here's the code I'm using in the view controller, which doesn't do anything at all:
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[textView resignFirstResponder];
}
Any suggestions?
That looks like correct code to me. Put a breakpoint in to make sure it's being called.

Recognize regular taps in table view on iPhone

I have a table view with custom cells and I recognize swipes in that cells. That works just fine but I'd like the table view to behave normally. When I tap the wherever on the table view I'd like cell to get selected and perform action tableView:didSelectRowAtIndexPath:
Any tips or ideas?
Thanks.
I assume you are implementing the various UIResponder methods in your UITableView cell subclass. If you want the rest of the stack to continue processing the events you can just pass them on:
- (void) touchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
//do something with touch
//...
//pass the event to super which cause it to continue along the chain as
//though you didn't do anything special with it
[super touchEnded:touch withEvent:event];
}