How to detect a tap outside a UITextField (to dismiss key board) - ios

My iPhone App has a numerical text-field (and some other controls). A num pad is shown when the user taps the text field. I like to dismiss this num pad (by [self.textField resignFirstResponder]) as soon as the
user taps on the view's background (easy to detect) but also when the user taps on any other control!
How can I detect that the user taps outside the text field (but not necessarily on the background)?

I always do this in viewDidLoad:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
and then implement:
- (void)dismissKeyboard
{
[self.view endEditing:YES];
}
Works like a charm :)

Just use:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}

Extending on #reecon's answer about touchesBegan. I wouldn't recommend to use it as you'd end up with a jumping keyboard up and down when the user taps repeatedly and believe me, it looks totally weird (at least it was on iOS 7.1.1 in one of my projects).
I'd go for the good old full screen UITapGestureRecognizer. You could also use a full screen UISwipeGestureRecognizer with a down direction - it would look and feel even cooler, as if the user is sliding down a keyboard.
Both gestures are added through the IB and require no code to set up.
Tapping on "other controls" is a totally different story though and you'd have to do it all by hand - no gestures can help you.

Related

Detect touch over TableView and still be able to scroll

I need to be able to detect immediate touch and get its position. (so didSelectRowAtIndexPath can't help us since it does not act immediately when scrolling up and down fast, you need to breathe in and select one by one)
Already tried everything I can think of. Touches began in each cell does not work because it suddenly behaves like didSelectRowIndexPath when implemented in custom cell class. Same result with TableViewController, the nature of touches began (you touch it, respond right away) just won't work.
* I'm not trying to TAP. Need to be able to get TOUCH (TapGesture does not respond when swiping very carefully/slowly but touches began always does) *
Not sure it's what you need, but you can create a TapGestureRecognizer.
You will likely run into conflicts with the UITableView's own gesture recognisers, but there are mechanisms to solve these which should hopefully let you achieve your desired behaviour (look up requireGestureRecognizerToFail and UIGestureRecognizerDelegate's gestureRecognizerShouldBegin and shouldRecognizeSimultaneouslyWithGestureRecognizer).
Try this.
In cellForIndexpath method.
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
singleFingerTap.delegate=self;
cell.contentView.tag=indexPath.row;
[cell.contentView addGestureRecognizer:singleFingerTap];
//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"%ld",(long)recognizer.view.tag);
}
I think what you need to do, add UILongPressGestureRecognizer to tableview, so normal touch will scroll and long press will do whatever you want to. Set its minimumPressDuration like 0.2 so it won't take much time. Add action for UILongPressGestureRecognizer and in that method get location like:
CGPoint touchPointInView = [sender locationInView: self.view]; //location reespective to view
CGPoint touchPointInView1 = [sender locationInView: tableView]; //location respective to tableview

Accessing the Status Bar

So, I'd like to receive touches from the status bar anywhere, any view, from the app. Well actually only specific views, like home screens and root view controllers say from a view of a tab view controller.
So my goal is to: hold down the status bar to dismiss the current view, like a back button.
The reason why I'm using this approach as a back button is because the app I am making is a utility, like fully functional apps within one app. Therefore I do not want to use up space on the navbar item to display a back button.
Other fissures would be nice, like swipe left/right or double tap, but mostly holding down. I've seen alternatives like using a UIScrollView and use the - scrollsToTop method. Hmm not what I am looking for.
Hope this can help you.
When you tap the top area, which has 44 height, the event would be triggered.
- (void)viewDidLoad{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(navigationBack:)];
[self.view addGestureRecognizer:tapGesture];
}
- (void)navigationBack:(UITapGestureRecognizer *)tapGesture {
CGPoint p = [tapGesture locationInView:self.view];
if (CGRectContainsPoint(CGRectMake(0, 0, self.view.frame.size.width, 44), p)) {
NSLog(#"this where you put you navigation back event");
}
}

UIScrollViewKeyboardDismissModeOnDrag when nothing to scroll doesn't work

I'm trying to hide the keyboard with swipe gesture, in iOS 7 i know there is UIScrollViewKeyboardDismissModeOnDrag but this seems to work only when there is something to scroll, instead when the row result of the search are under the UIKeyboard but there are not enough row to scroll the view this UIScrollViewKeyboardDismissModeOnDrag is not working, because there is nothing to scroll, how i can dismiss the keyboard with a swipe gesture also when there is nothing to scroll?
The simplest and most elegant code wise, and the nicest feel in use, is to always set
self.tableView.alwaysBounceVertical = YES;
when using UIScrollViewKeyboardDismissModeOnDrag.
That way you can always drag vertically against a bounce, so the issue doesn't exist.
This work for me:
UISwipeGestureRecognizer * tapGesture = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:#selector(hideKeyBoard)];
[self.view addGestureRecognizer:tapGesture];
And the method:
-(void)hideKeyBoard {
[textViewOrTextField resignFirstResponder];
}
Hope that will help (at least it works for me).
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[myTextField resignFirstResponder];
}

How to make to keyboard has behavior like in default apps when text field is inside scroll view?

I have created in storyboard simple app (only one controller), I put scrollview and inside scrollview couple UITextFileds. Inside controller I have added function like
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.name resignFirstResponder];
[self.number resignFirstResponder];
// I have tried with and without this line but doesn't work
[self.scrollView resignFirstResponder];
}
(name, number are Outlets of UITextField, scrollView is Outlet of UIScrollView). When I click on any of those text fields keyboard pops up but when I finish typing I cannot hide keyboard.
(In previous version I didn't have scrollview and keyboard hides when I click out the text field). How to make to keyboard has behavior like in default apps, how to hide ?
I'm assuming you want to just be able to tap away from the keyboard and have it dismissed right? Just do this:
UITapGestureRecognizer *myTapz = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(userTapped)];
myTapz.numberOfTapsRequired=1;
myTapz.cancelsTouchesInView=NO;
[self.view addGestureRecognizer:myTapz];//or do self.WhateverYourOtherViewIsCalled..tableview? scrollView?
[myTapz release];
And then in your selector:
-(IBAction)userTapped
{
[whateverYourTextFieldIsCalled resignFirstResponder];
}
In your view controller:
[self.view endEditing:YES];
This will dismiss the keyboard no matter what field is the first responder. I think there are some exceptions, but for what you're doing it should work fine.
Also touchesBegan is a UIView method, not a UIViewController method. If you're putting it inside your UIScrollView, the scroll view's panGestureRecognizer is going to prevent touchesBegan from being called. Also when overriding touchesBegan, or other touches methods, you typically want to call super as well.
ttarules's suggestion for creating a gesture recognizer is the best way for detecting touches. You can use touchesBegan inside the view, just know that other gesture recognizers can prevent it from being called (see Session 121 - Advanced Gesture Recognition from WWDC 2010).
endEditing is the best way to dismiss the keyboard because it works even after you add other fields.

How do I subclass UISegmentedControl so that individual segments recognize a UILongPressGestureRecognizer?

First off this question has been helpful in my understanding of how to subclass UIButton for long presses. I would like to do the same for UISegmentedControl, however I don't see how I would be able to identify which segment was held down since UISegmentedControl does allow direct access to it's segments (UISegmentedControl.h shows them as private). I could just customize a few UIButtons to look like an UISegmentedControl however I would also have to implement the momentary switch logic. Which wouldn't be a big deal but subclassing UISegmentedControl seems cleaner to me.
BTW, I'm using this control to imitate a radio's preset controls: tap to go to a saved station and hold to assign the current station to that segment.
I tried this without subclassing and it seems to work.
UILongPressGestureRecognizer* recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(pressGesture:)];
recognizer.delegate = self;
[mySegCtrl addGestureRecognizer:recognizer];
[recognizer release];
...
-(void)pressGesture:(UILongPressGestureRecognizer*)gesture
{
NSLog(#"pressGesture %#", gesture);
}
Long press first selects the segment then fires the gesture. If you aren't getting the callback check my code - I got stuck for a while because I wasn't setting recognizer.delegate=self.

Resources