I am working on a small children's game for my son that involves timing on the virtual keyboard.
Is possible to detect when a key on the virtual keyboard is pressed? I.e. get a touch notification (touchesBegan)? I do not need to know which key is pressed, just if and when the press action started.
For TextView you can use...
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
- (void)textViewDidChange:(UITextView *)textView
For TextField you can use...
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
See UITextViewDelegate and UITextFieldDelegate on Apple website.
It's not possible to get the touch events directly from the virtual keyboard. However, you could use a UITextField that you place offscreen, so that it's not visible and call becomeFirstResponder to show the keyboard. Then, as Khomsan suggested, you could implement the delegate method textView:shouldChangeTextInRange: to be notified whenever a key is pressed.
A cleaner possibility would be to write a custom UIControl that implements the UIKeyInput protocol. You would only need to provide implementations for insertText:, deleteBackward and hasText (for this one, you can simply always return YES). To make the keyboard visible, you would again have to call becomeFirstResponder for your custom control.
Both of these methods have in common that you only will be notified when the key is released (so that text is entered), not when the touch actually begins. As I said, it's not possible to get the tochesBegan event directly. If you need that, you would probably have to implement your own onscreen keyboard.
Yes you can just use:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//do what you need
[super touchesBegan:touches withEvent:event];
}
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.
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 am wondering why I am not able to find any help regarding the keyboard keyup/keydown events, I actually want to detect which key is been pressed by the user via keyboard on iphone while inputting the text in the UITextField.
You can use this delegate method to get the character that's being entered into a UITextField:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
For example:
if ([string isEqualToString:#"z"]){
// z is being typed.
}
Just make sure you've said your UITextField's delegate to the class file where you implement this.
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.
I've got one text entry box in my iphone app, when you touch it in the simulator, the keyboard pops up. But there's no way to get rid of it.
Other web pages give solutions, without explaining why they should work, and they don't work for me.
One says make the text box's delegate your uiview then call resignfirstresponder on the object, but it never gets called.
Any suggestions? Can anybody explain what's actually going on? I can figure it out myself if I knew what the design paradigm was...
Maybe I should just put a "go" button so I have something to get the focus away from the textfield?
One way to do it is to set an object as the delegate to the text field and implement
- (BOOL)textFieldShouldReturn:(UITextField *)textField
in which you call [textField resignFirstResponder]
This will cause the keyboard to disappear when they push the return/go/done button (whatever you set the bottom right keyboard key to be).
See the UITextFieldDelegate reference for more info.
To dismiss keyboard you can use TextField Delegate.
To use this follow these steps...
1. In you viewController.h add the delegate declaration like this:
#interface ViewController : UIViewController <UITextFieldDelegate> {
}
2. In your viewController.m call this method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
3. Then write a code like this:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
4. Final step is to set the textField's delegate:
- (void)viewDidLoad {
[super viewDidLoad];
self.textField.delegate = self;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField in your delegate is called when the return button is pressed.
You want to call [textField resignFirstResponder] and then return YES. That should do the trick. Also make sure the delegate is set. If in doubt, add a break point or NSLog and verify.
You can simply type the following:
textfield.endEditing(true)
Where textfield is the name of your UITextField.