I am trying to figure out how to dismiss the keyboard and trigger a method when the user taps outside of a UITextField
in TableViewCell.m:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[self.delegate cellDidBeginEditing:self];
}
in ViewController.m:
-(void)cellDidBeginEditing:(TableViewCell *)editingCell
{
_editingOffset = _tableView.scrollView.contentOffset.y - editingCell.frame.origin.y;
for (TableViewCell *cell in [_tableView visibleCells]) {
[UIView animateWithDuration:0.3
animations:^{
cell.frame = CGRectOffset(cell.frame, 0, _editingOffset);
if (cell != editingCell) {
cell.alpha = 0.25;
}
}];
}
}
the cellDidBeginEditing: method displaces the cell to the top and shades the other cells grayish.
I have another method, cellDidEndEditing: which does the opposite of this, and the code is not really needed.
As of now, selecting, for example, "cell2" when editing "cell1" just triggers cellDidBeginEditing for "cell2"
I want the keyboard to dismiss and cellDidEndEditing to trigger when I click outside of "cell1"
Try implementing and calling these functions:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesBegan:withEvent");
[self.view endEditing:YES];
[super touchesBegan:touches withEvent:event];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.firstTextField resignFirstResponder];
[self.secondTextField resignFirstResponder];
return YES;
}
This should make it so that when you touch any where outside of the two textFields, the keyboard automatically dismisses.
Related
I have a tableview with 8 custom cells. in the 8th cell I added a scrollView with paging enabled so I can show page 1 and page 2 (or 3, 4... 10) without have a very high cell.
The problem is with the scrollView I can't use didSelectRowAtIndexPath because the cell is behind the scrollView so I'm trying to detect scrollView tap (not swipe).
I played with touchesBegan and touchesEnded but they are never called (I know touches work with UIView only, but maybe.....)
Any help is very appreciated.
Thanks,
Max
There is a trick Apple recommends to use in this case, in theirs WWDC 2014 session "Advanced scrollviews" (See Demo starting from 8:10):
[cell.contentView addSubview:_scrollView];
[_scrollView setUserInteractionEnabled:NO];
[cell.contentView addGestureRecognizer:_scrollView.panGestureRecognizer];
That's all what needs to be done, no need to override touchesBegan:, touchesMoved: and others.
I used solution based on overriding of touchesBegan:, touchesMoved:, touchesEnded: and touchesCancelled: previously, but sometimes it caused a weird behaviour: when select a certain cell, method -tableView:didSelectRowAtIndexPath: was called for cell with different indexPath.
Solution from Apple has no side effects so far and looks more elegant.
There is also an elegant resolution:
Create a SubClass from UIScrollView and override the following methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesMoved:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesCancelled:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesEnded:touches withEvent:event];
}
Passing every touch to the superview of the scroll view and then the didSelectRowAtIndexPath will be called.
Solved subclassing both uitableviewcell and uiscrollview.
It worked for my needs. Hope it can help.
Max
myScrollView.h
#import <UIKit/UIKit.h>
#interface myScrollView : UIScrollView {
}
#end
myScrollView.m
#import "myScrollView.h"
#implementation myScrollView
- (id)initWithFrame:(CGRect)frame {
return [super initWithFrame:frame];
}
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
NSLog(#"touch scroll");
// If not dragging, send event to next responder
if (!self.dragging)
[self.nextResponder touchesEnded: touches withEvent:event];
else
[super touchesEnded: touches withEvent: event];
}
myCell.h
#import <UIKit/UIKit.h>
#interface myCell : UITableViewCell {
}
#end
myCell.m
#import "myCell.h"
#implementation myCell
- (id)initWithFrame:(CGRect)frame {
return [super initWithFrame:frame];
}
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
NSLog(#"touch cell");
// If not dragging, send event to next responder
[super touchesEnded: touches withEvent: event];
}
RootViewController.h
#import <UIKit/UIKit.h>
#class myCell;
#class myScrollView;
#interface RootViewController : UITableViewController {
myCell *cell;
myScrollView *scrollView;
}
#end
RootViewController.m
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
// my custom cell
cell = [[myCell alloc] init];
if (cell == nil) {
cell = [[[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// the custom scroll view
scrollView = [[myScrollView alloc] initWithFrame:cell.frame];
scrollView.contentSize = CGSizeMake(640, 40);
[cell.contentView addSubview:scrollView];
//something to add in scrollView
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 20)];
label.text = #"some text";
[scrollView addSubview:label];
// Configure the cell.
return cell;
}
The selected answer is correct, but I updated the code based on a bug I was getting.
In the subclassed scroll view add the following code.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.dragging) {
[super touchesMoved:touches withEvent:event];
} else {
if ([self.delegate isKindOfClass:[UITableViewCell class]]) {
[(UITableViewCell *)self.delegate touchesCancelled:touches withEvent:event];
}
[self.superview touchesMoved:touches withEvent:event];
}
}
If your self.delegate is not the UITableViewCell, than replace that property with a property to your cell.
The cell needs to retrieve the cancel touch event during movement to prevent the undesired results. It can be easily reproducible as follows.
Highlight the cell (assuming the scroll view is over the whole cell, if not highlight the scroll view)
While the cell is highlighted, drag the table view
Select any other cell and now the previously highlighted cell will retrieve the didSelectCell state
Another point to mention is that order matters! If the self.delegate is not called before the self.superview then the highlighted state wont happen.
I found the simplest solution for my needs:
subclass UIScrollView touchesEnded method and post a notification.
In the UITableview add an observer in viewdidAppear (remove it in viewdiddisappear) to call a function that call tableview didSelectRowForIndexPath.
Something like this (swift version)
// myScrollView.swift
import UIKit
class myScrollView: UIScrollView {
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
NSNotificationCenter.defaultCenter().postNotificationName("selectTVRow", object: nil)
}
}
In your tableView:
// ItemsList.swift
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "selectFourthRow", name: "selectTVRow", object: nil)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "selectfourthrow", object: nil)
}
func selectFourthRow() {
let rowToSelect:NSIndexPath = NSIndexPath(forRow: 4, inSection: 0);
self.tableView(self.tableView, didSelectRowAtIndexPath: rowToSelect);
}
/*
.... rest of your tableview Datasource and Delegate methods...
numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath
*/
How can I dismiss the keyboard in iOS when the textfield does not have an IBOutlet to the view controller? My case is a UITableView with dynamic prototype cells. One of those cells contains a UITextField, however I cannot add an IBOutlet because outlets are not allowed in repeating content.
So how can I achieve to dismiss the keyboard when textfield does not have outlet?
Add any one method in your ViewController.m file :
Choice -1
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
Choice -2
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(resignFieds)];
[self.view addGestureRecognizer:tap];
- (void)resignFieds {
//choice - 1 , check the all subviews and resign textfield
for (UIView * txt in self.view.subviews){
if ([txt isKindOfClass:[UITextField class]] && [txt isFirstResponder]) {
[txt resignFirstResponder];
}
else
{
[self.view endEditing:YES];
}
}
//choice 2 , no need to check any subviews ,
[self.view endEditing:YES];
Note : use any one choice
}
You can use this:
[view endEditing:YES];
try these..
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(taped:)];
[tap setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:tap];
-(void)taped:(UITapGestureRecognizer*)gesture
{
[self.view endEditing:YES];
}
OR
you can do these also..
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if (![[touch view] isKindOfClass:[UITextField class]])
{
[self.view endEditing:YES];
}
[super touchesBegan:touches withEvent:event];
}
i hope it helps..
Try this :-
In Swift:-
UIApplication.sharedApplication().sendAction(Selector("resignFirstResponder"), to: nil, from: nil, forEvent: nil)
In Objective-C:-
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
Explanation:-
We can send an action to the first responder by calling sendAction:to:from:forEvent on the UIApplication singleton and passing nil as the target and in your case your first responder is your textfield.
I assume that you’ve created custom dynamic prototype cell which have UITextField in it.
No need to have IBOutlet of UITextField in your ViewController class where you have added UITableView.
Create Custom TableViewCell Class, then create IBOutlet of UITextField in Custom TableViewCell Class.
#interface SimpleTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UITextField *simpleTxtField;
#end
Set TableViewCell Class to Custom TableViewCell class say “SimpleTableViewCell”. by selecting TableViewCell and selecting Identity Inspector icon in Right side pane in Xcode.
in your ViewController class confirm to UITextField Delegate. like this.
#interface ViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITableView *simpleTableView;
#end
implement UITextField delegate Method.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
then in tableView:cellForRowAtIndexPath method of UITableView Datasource set your Custom TableViewCell’s (SimpleTableViewCell) TextField Delegate to self.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SimpleTableViewCell *cell = [self.simpleTableView dequeueReusableCellWithIdentifier:#"simpleCell" forIndexPath:indexPath];
cell.simpleTxtField.delegate = self;
return cell;
}
and whenever you select TextField of Cell a Keyboard will display and when you click return key a TextField Delegate method will get call and Keyboard will get dismiss.
Hope this will help.
Currently I'm using this third-party library in my project https://github.com/EddyBorja/MLPAutoCompleteTextField. This library is used to show the suggestion list based on user input.
I did setup the text field like this
self.searchTextField = [[MLPAutoCompleteTextField alloc] initWithFrame:CGRectMake(0, 0, 250, 30)];
[self.searchTextField setBorderStyle:UITextBorderStyleRoundedRect];
self.searchTextField.backgroundColor = [UIColor whiteColor];
self.searchTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
self.searchTextField.textColor = [UIColor blackColor];
self.searchTextField.returnKeyType = UIReturnKeyDone;
self.searchTextField.placeholder = #"Enter name to search";
self.searchTextField.autocorrectionType = UITextAutocorrectionTypeNo;
self.searchTextField.delegate = self;
self.searchTextField.autoCompleteDelegate = self;
self.searchTextField.autoCompleteDataSource = self;
Implement the Datasource protocol as below
- (NSArray *)autoCompleteTextField:(MLPAutoCompleteTextField *)textField possibleCompletionsForString:(NSString *)string {
return #[#"AAA", #"BBB", #"CCC", #"DDD"];
When I input something to the text field, the drop down list was shown but when I tap on a cell in the drop down list, the list dissappeared without completing any words in the text field.
Anyone experienced this problem please explain to me where I was wrong. Thanks in advance.
I had the same issue awhile back. I happened to be using MLPAutocomleteTextField inside a UITableView, so all the touch events were likely intercepted by the tableview.
I worked around this issue by setting the autoCompleteTableAppearsAsKeyboardAccessory of my MLPAutocomleteTextField instance to TRUE to enable enable autocomplete as a keyboard accessory. This allowed me to select my autocomplete options. Hopefully this solves your issue as well. :)
I solved it by subclassing my UITableViewCell, a little tricky but it's working for me:
#import "AutoCompleteTableViewCell.h"
#interface AutoCompleteTableViewCell()
#property (nonatomic, assign) BOOL selectedCell;
#end
#implementation AutoCompleteTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
self.selectedCell = NO;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
UIView* hitView = [super hitTest:point withEvent:event];
if (hitView != nil)
{
[self.superview bringSubviewToFront:self];
}
return hitView;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
CGRect rect = self.bounds;
BOOL isInside = CGRectContainsPoint(rect, point);
if(!isInside)
{
for (UIView *view in self.subviews)
{
isInside = CGRectContainsPoint(view.frame, point);
if(isInside)
break;
}
}
if (!self.selectedCell) {
self.selectedCell = YES;
id view = [self superview];
while (view && [view isKindOfClass:[UITableView class]] == NO) {
view = [view superview];
}
UITableView *tableView = (UITableView *)view;
NSIndexPath *indexPath = [tableView indexPathForCell:self];
[tableView.delegate tableView:tableView didSelectRowAtIndexPath:indexPath];
}
return isInside;
}
Then delegate method is called:
- (void)autoCompleteTextField:(MLPAutoCompleteTextField *)textField
didSelectAutoCompleteString:(NSString *)selectedString
withAutoCompleteObject:(id<MLPAutoCompletionObject>)selectedObject
forRowAtIndexPath:(NSIndexPath *)indexPath;
in the following scenario clicking on the pencil turns the iz 1 text to be editable by making it becomeFirstResponder and the keyboard opens, I wish to close the keyboard when clicking on the "empty rows" or iz2.
how can i do that?
I've tried adding to the cellView
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self dismissKeyboard];
}
but it didn't work
You can hide keyboard using this:
[self.view endEditing:YES];
EDIT
Add gesture in where you can call becomeFirstResponder.
- (void)showKeyboard
{
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hide)];
[self.tableView addGestureRecognizer:gesture];
}
and remove it in hide method,
- (void)hide
{
[self.view endEditing:YES];
[self.view removeGestureRecognizer:self.view.gestureRecognizers[0]];
}
Just call:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}
Or:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSIndexPath *indexPathForYourCell = [NSIndexPath indexPathForRow:0 inSection:0];
YourCustomCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPathForYourCell];
[cell.iz1TextField resignFirstResponder];
}
my final solution was something similar to what #caglar suggested here is the code i've written inside tableviewcontroller:
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
}
-(void)dismissKeyboard
{
[self.view endEditing:YES];
}
I am new in iOS development. I want to hide the keyboard when tapping outside of a UITextView.
My TextView is in a cell from an UITableView. The problem is that I have a Toolbar at the top and my buttons doesn't react anymore. I implemented the method "shouldReceiveTouch" but my test is not correct i think. Any ideas? Thank you and sorry for my bad english..
In my ViewDidLoad:
tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
tap.delegate = self;
[self.view addGestureRecognizer:tap];
note: tap is an UITapGestureRecognizer property.
Implemented methods:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIBarButtonItem class]]) {
return NO;
}
return YES;
}
-(void)dismissKeyboard {
[tview resignFirstResponder];
}
UIBarButtonItem is not a subclass of UIView, hence the shouldReceiveTouch still return YES.
Try to exclude the whole UIToolbar or just add the tap gesture recognizer in the UITableViewCell when you initialize the cell in cellForRowAtIndexPath.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIToolbar class]]) {
return NO;
}
return YES;
}
You should add your gesture to table view.
tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
tap.delegate = self;
[tblView addGestureRecognizer:tap];
use didScroll method of UIScrollView delegate to resign keyboard.TableView is also subclass of UIScrollView so it should work.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[tview resignFirstResponder];
}
or use this one
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[tview resignFirstResponder];
}
If you still want to use gesture then add gesture to UIView or self.view or superView of tableView
instead of adding it to tableView
Try following code :----
Keep you code as it is and add this method
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[tview resignFirstResponder];
}
in viewDidLoad set self.view.userInteractionEnabled = yes;
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([touch view] == tview) {
[tview resignFirstResponder];
}
}