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.
Related
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.
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.
Is there any simple method other than the one seen in
http://www.neoos.ch/news/46-development/54-uikeyboardtypenumberpad-and-the-missing-return-key
to dismiss a Number pad in iPhone??
This code for a single text Field seems a lot.!!
You can also do this by casting the background view to be a UIControl and then hook up a touch event to the controller's [self.view endEditing:YES];
You do this by changing the class of the base view in the xib to to be a UIControl instead of UIView
This means that the keyboard can be dismissed by touching the background.
HI Finally from all the suggestions i Got it!!
Make your keyboard as Number Pad on Xib and put the following code in the .m file after connecting all the textFields..
-(void)touchesBegan NSSet *)touches withEvent UIEvent *)event
{
[txt11 resignFirstResponder];
[txt22 resignFirstResponder];
}
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.
I'm not sure why this is so hard. I have a UISearchBar at the top of my page. When the user types into that UISearchBar, it will automatically filter the results in the UITableView that is below the search bar. There is no need for a Search button since I search when keys are pressed.
The flow of the application is that the user types a search in the search bar (with the keyboard being displayed) and then will scroll the results in the table view - at which point the keyboard needs to disappear.
I'm having a hard time getting the keyboard to disappear.
I know I need to do:
[searchBar resignFirstResponder];
to get the keyboard to disappear but I can't find what delegate I need to perform this on. I want to do this as soon as the user touches the table view.
Any ideas?
Try this:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[searchBar resignFirstResponder];
}
It worked for me
I think the easiest (and best) way to do this is to subclass your global view and use hitTest:withEvent method to listen to any touch. Touches on keyboard aren't registered, so hitTest:withEvent is only called when you touch/scroll/swipe/pinch... somewhere else, then call [self endEditing:YES].
This is better than using touchesBegan because touchesBegan are not called if you click on a button on top of the view. It is also better than using a dim screen because in a complexe and dynamic user interface, you can't put dim screen every where. Also, it's better than calling [searchBar resignFirstResponder], because you may have many text fields on screen, so this works for all of them.
You might want to do it as Cydia (jailbroken packaging UI) does it - there is a search button, and when you press the search button, it closes the keyboard. The results are still filtered as you type for a preview.
Since the results are going to be in a table view, use UIScrollView's delegate (to which UITableView responds) method - (void)scrollViewDidScroll:(UIScrollView *)scrollView.
You'll need to have your view controller respond to the UITableView's data source and delegate (in the .h file):
<UITableViewDataSource, UITableViewDelegate>
Than in your initialization method in the .m file add:
self.tableView.dataSource = self;
self.tableView.delegate = self;
Finally, add this method:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[self.view endEditing:YES];
}
This will make the UISearchBar lose focus, and the keyboard will hide.
One possibility is that the UISearchBar belongs to a controller, that is displayed in UIModalPresentationFormSheet.
I had the same problem and found out that this is related to the method "disablesAutomaticKeyboardDismissal" of UIViewController.
The Apple documentation states the following:
Override this method in a subclass to allow or disallow the dismissal
of the current input view (usually the system keyboard) when changing
from a control that wants the input view to one that does not. Under
normal circumstances, when the user taps a control that requires an
input view, the system automatically displays that view. Tapping in a
control that does not want an input view subsequently causes the
current input view to be dismissed but may not in all cases. You can
override this method in those outstanding cases to allow the input
view to be dismissed or use this method to prevent the view from being
dismissed in other cases.
The default implementation of this method returns YES when the modal
presentation style of the view controller is set to
UIModalPresentationFormSheet and returns NO for other presentation
styles. Thus, the system normally does not allow the keyboard to be
dismissed for modal forms.
In my case, I displayed the search bar within the navigation bar, so I had to create a subclass of UINavigationViewController that overrides the method as follows:
- (BOOL)disablesAutomaticKeyboardDismissal {
return NO;
}
After that resignFirstResponder would finally make the keyboard disappear.
Might be super late to answer but this might help anyone in future. This particular piece of code worked for me. P.S. I don't own this solution, found some time ago on the net itself.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if ([self.srchBar isFirstResponder] && [touch view] != self.srchBar)
{
[self.srchBar resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}
Given a view with a searchBar variable, add this method to the view:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?
{
if searchBar.isFirstResponder && !searchBar.point(inside: point, with: event){
searchBar.resignFirstResponder()
}
return super.hitTest(point, with: event)
}