通过触摸UITableView的背景来closures键盘
我有UITableView
与UITextField
s作为单元格。 我想在触摸UITableView
的背景时closures键盘。 我试图通过创build一个UITableView
的大小的UIButton
并将其放在UITableView
后面。 唯一的问题是即使触摸在UITableView上, UIButton
也能捕捉所有的触摸。 我究竟做错了什么?
谢谢!
这很容易通过创build一个UITapGestureRecognizer对象来完成(默认情况下,这将在一次抽头中检测到一个“手势”,因此不需要进一步的自定义),指定触发手势时的目标/动作,然后附加手势识别器对象到你的桌子视图。
例如也许在你的viewDidLoad方法中:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)]; [self.tableView addGestureRecognizer:gestureRecognizer];
hideKeyboard方法可能如下所示:
- (void) hideKeyboard { [textField1 resignFirstResponder]; [textField2 resignFirstResponder]; ... ... }
请注意,在触摸UITextField对象内部时,手势不会被触发。 它是在UITableView背景,页脚视图,标题视图和单元格内的UILabels中被触发的。
如果您设置了以下选项,UITapGestureRecognizer解决scheme可以处理表格单元格select:
gestureRecognizer.cancelsTouchesInView = NO;
这是做这个最好的方法。 只要做到这一点
[self.view endEditing:YES];
要么
[[self.tableView superView] endEditing:YES];
你也可以从Storyboard中完成:
由于UITableView是UIScrollView的子类,下面实现一个委托方法提供了一个非常简单,快速的解决scheme。 因为视图层次反省,并且find当前响应者并且要求它辞去响应者状态,所以甚至不需要涉及“resignFirstResponder”。
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self.view endEditing:YES]; }
并记得添加UIScrollViewDelegate到头文件。
首先,通过添加UIScrollViewDelegate来监听UIViewController中的scrollViewWillBeginDragging:
在.h文件中:
@interface MyViewController : UIViewController <UIScrollViewDelegate>
在.m文件中:
- (void)scrollViewWillBeginDragging:(UIScrollView *)activeScrollView { [self dismissKeyboard]; }
然后听取其他互动:
- (void)setupKeyboardDismissTaps { UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; swipeUpGestureRecognizer.cancelsTouchesInView = NO; swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp; [self.tableView addGestureRecognizer:swipeUpGestureRecognizer]; UISwipeGestureRecognizer *swipeDownGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; swipeDownGestureRecognizer.cancelsTouchesInView = NO; swipeDownGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown; [self.tableView addGestureRecognizer:swipeDownGestureRecognizer]; UISwipeGestureRecognizer *swipeLeftGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; swipeLeftGestureRecognizer.cancelsTouchesInView = NO; swipeLeftGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft; [self.tableView addGestureRecognizer:swipeLeftGestureRecognizer]; UISwipeGestureRecognizer *swipeRightGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; swipeRightGestureRecognizer.cancelsTouchesInView = NO; swipeRightGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight; [self.tableView addGestureRecognizer:swipeRightGestureRecognizer]; UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; tapGestureRecognizer.cancelsTouchesInView = NO; [self.tableView addGestureRecognizer:tapGestureRecognizer]; }
然后执行dismissKeyboard:
- (void)dismissKeyboard { NSLog(@"dismissKeyboard"); [yourTextFieldPointer resignFirstResponder]; }
如果和我一样,你想在一个自定义表格单元格中closuresUITextField的键盘:
- (void)dismissKeyboard { NSLog(@"dismissKeyboard"); CustomCellClass *customCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; [customCell.textFieldInCell resignFirstResponder]; }
希望能帮助任何人search!
我是这样做的:
在你的TableViewController中创build一个方法来停用第一响应者(这将是你的TextBox)
- (BOOL)findAndResignFirstResonder:(UIView *)stView { if (stView.isFirstResponder) { [stView resignFirstResponder]; return YES; } for (UIView *subView in stView.subviews) { if ([self findAndResignFirstResonder:subView]) { return YES; } } return NO; }
在tableView:didSelectRowAtIndexPath:
调用前面的方法:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { ... [self findAndResignFirstResonder: self.view]; ... }
以下是您编码乐趣的快速版本:
它添加了一个轻击手势识别器,然后解散键盘。 没有出口的TextField是必需的!
override func viewDidLoad() { super.viewDidLoad() view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleTap:")) } func handleTap(sender: UITapGestureRecognizer) { if sender.state == .Ended { view.endEditing(true) } sender.cancelsTouchesInView = false }
tableView.keyboardDismissMode = .onDrag
@interface DismissableUITableView : UITableView { } @end @implementation DismissableUITableView - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.superview endEditing:YES]; [super touchesBegan:touches withEvent:event]; } @end
然后确保在你的Nib文件中,你将UITableView的types设置为DismissableUITableView …..也许我可以想到这个类更好的名字,但是你明白了。
如果您的目标是iOS7,则可以使用以下选项之一:
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
前者会在桌面视图滚动时将屏幕上的键盘设置为屏幕animation,而后者则会像股票消息应用程序一样隐藏键盘。
请注意,这些来自UITableView
inheritance自的UIScrollView
。
我有一个UITableViewController
和实现touchesBegan:withEvent:
没有为我工作。
这是什么工作:
迅速:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { view.endEditing(true) }
Objective-C的:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self.view endEditing:YES]; }
UITableView是UIScrollView的一个子类。
我做的方式是听用户的滚动事件,然后resignFirstResponder。 这里是在您的代码中实现的UIScrollViewDelegate方法;
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
当遇到这些问题时,我发现最好的办法是研究每个对象和父类的委托协议(在本例中为UITableViewDelegate,UIScrollViewDelegate)。NS对象触发的事件数量非常大,全面。也更容易实现一个协议,然后inheritance任何东西。
我有同样的问题,这是我的解决scheme,它完全适合我:
在实现<UITextFieldDelegate>
的视图或视图控制器中
(在我的情况下,我有一个自定义的UITableViewCell
称为TextFieldCell),
将UITapGestureRecognizer
声明为一个属性:
@interface TextFieldCell : UITableViewCell <UITextFieldDelegate> { UITextField *theTextField; UITapGestureRecognizer *gestureRecognizer; } @property (nonatomic,retain) UITextField *theTextField; @property (nonatomic,retain) UITapGestureRecognizer *gestureRecognizer;
并在你的视图/控制器中初始化它:
self.gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard:)];
在- (void)textFieldDidBeginEditing:(UITextField *)textField
方法中,使用superView
移动到您的tableView并调用addGestureRecognizer
:
[self.superview.superview addGestureRecognizer:gestureRecognizer];
并在- (void)textFieldDidEndEditing:(UITextField *)textField
,只需删除手势识别器:
[self.superview.superview removeGestureRecognizer:gestureRecognizer];
希望它有帮助。
我希望我的单元格在单元格的任何部分被选中时打开键盘,如果在单元格的任何地方点击,则closures它。 打开键盘:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; if (selected) { [self.textField becomeFirstResponder]; } }
(注:我已经subclassed单元格,但你可以很容易地实现这个在tableView:didSelectRowAtIndexPath:
UITableView
委托方法)
这样做的意思是,如果你点击单元格的顶部解决scheme两次,键盘会摇动,首先手势识别器试图closures键盘,第二个单元格重新select,并试图打开键盘。
解决方法是检查点击是否发生在当前选中的单元格内:
- (void)viewDidLoad { [super viewDidLoad]; //gesture recognizer to close the keyboard when user taps away UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard:)]; tap.cancelsTouchesInView = NO; [self.tableView addGestureRecognizer:tap]; } -(void)dismissKeyboard:(UIGestureRecognizer*)tapGestureRecognizer { if (!CGRectContainsPoint([self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]].frame, [tapGestureRecognizer locationInView:self.tableView])) { [self.view endEditing:YES]; } }
我find了一个很好的解决scheme。
需要使用UIGestureRecognizerDelegate和方法– gestureRecognizer:shouldReceiveTouch:。
将手势识别器添加到TableView中,如下所示:
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)]; tapGestureRecognizer.cancelsTouchesInView = NO; tapGestureRecognizer.delegate = self; [self.suggestedTableView addGestureRecognizer:tapGestureRecognizer]; [tapGestureRecognizer release];
然后,实现shouldReceiveTouch委托方法来拒绝在UITableViewCell类中执行的触摸操作。 只有在UITableViewCell类外执行触摸操作时,才会调用hideKeyboard方法。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if([touch.view isKindOfClass:[UITableViewCell class]]) { return NO; } // UITableViewCellContentView => UITableViewCell if([touch.view.superview isKindOfClass:[UITableViewCell class]]) { return NO; } // UITableViewCellContentView => UITableViewCellScrollView => UITableViewCell if([touch.view.superview.superview isKindOfClass:[UITableViewCell class]]) { return NO; } return YES; // handle the touch } - (void) hideKeyboard{ [textField resignFirstResponder]; }
有Swift 3版本没有阻塞单元格上的水龙头。
在viewDidLoad()
方法中:
let dismissKeyboardGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard)) dismissKeyboardGesture.cancelsTouchesInView = false tableView.addGestureRecognizer(dismissKeyboardGesture)
hideKeyboard
看起来像这样:
func hideKeyboard() { view.endEditing(true) }
我正在寻找解决scheme,并没有find任何适合我的代码,所以我这样做:
http://82517.tumblr.com/post/13189719252/dismiss-keyboard-on-uitableview-non-cell-tap
它基本上是前面提到的方法的组合,但不需要子类化或创build背景button。
只需使用UITapGestureRecognizer并cancelsTouchesInView = NO
意味着点击单元格和UITextViews也会触发隐藏。 如果你有多个UITextViews,并且你点击下一个,这是不好的。 键盘将开始隐藏,然后下一个textView成为firstResponder,键盘再次变为可见。 为了避免这种情况,请检查水龙头的位置,如果水龙头不在水池上,只隐藏键盘:
// init UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapTableView:)]; tapRecognizer.cancelsTouchesInView = NO; [self.tableView addGestureRecognizer:tapRecognizer]; // Hide on tap - (void)didTapTableView:(UITapGestureRecognizer *)tap { CGPoint point = [tap locationInView:tap.view]; [self.view endEditing:!CGRectContainsPoint([self.tableView rectForRowAtIndexPath:[self.tableView indexPathForRowAtPoint:point]], point)]; }
为了使scrollViewWillBeginDragging:
被触发,tableView的scrollEnabled
属性必须是YES
// Hide on scroll - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self.view endEditing:YES]; }
为什么你想创build一个充满文本字段的表格? 您应该使用包含文本字段的每一行的详细视图。 当您推送详细视图时,请确保您调用“[myTextField becomeFirstResponder]”,以便用户只需从表格列表中单击一下即可开始编辑。
如果你愿意inheritance(唉!)你的表视图, 像这样的东西可能会工作:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { BOOL backgroundTouched = YES; for (UITouch *touch in touches) { CGPoint location = [touch locationInView:self]; for (UITableViewCell *cell in self.visibleCells) { if (CGRectContainsPoint(cell.frame, location)) { backgroundTouched = NO; break; } } } if (backgroundTouched) { for (UITableViewCell *cell in self.visibleCells) { // This presumes the first subview is the text field you want to resign. [[cell.contentView.subviews objectAtIndex:0] resignFirstResponder]; } } [super touchesBegan:touches withEvent:event]; }
如果你想在按下回车键的时候closures键盘,你可以简单地在textField中添加下面的代码,例如:
- (BOOL)textFieldShouldReturn:(UITextField *)atextField { [textField resignFirstresponder]; }
一些文本框可能有一个select器视图或其他一些子视图,所以在这种情况下,上述方法不起作用,所以在这种情况下,我们需要使用UITapGestureRecognizer类,即将以下代码片段添加到viewDidLoad方法,即:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; [self.view addGestureRecognizer:tap];
现在简单地添加resign responder到select器方法,即:
-(void)dismissKeyboard { [textField resignFirstResponder]; }
希望它有帮助,谢谢:)
许多有趣的答案。 我想编译不同的方法到我认为最适合UITableView场景(这是我通常使用的场景)的解决scheme:我们通常需要的是基本上隐藏键盘的两种情况:在Text UI元素之外轻敲,或者向下/向上滚动UITableView。 我们可以通过TapGestureRecognizer轻松添加第一个场景,第二个场景通过UIScrollViewDelegate的scrollViewWillBeginDragging:方法。 业务的第一步,隐藏键盘的方法:
/** * Shortcut for resigning all responders and pull-back the keyboard */ -(void)hideKeyboard { //this convenience method on UITableView sends a nested message to all subviews, and they resign responders if they have hold of the keyboard [self.tableView endEditing:YES]; }
这种方法会在UITableView视图层次结构中的子视图的任何textField UI上放弃,所以比单独放弃每个元素更加实用。
接下来,我们通过一个外部的点击手势来照顾解雇:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self setupKeyboardDismissGestures]; } - (void)setupKeyboardDismissGestures { // Example for a swipe gesture recognizer. it was not set-up since we use scrollViewDelegate for dissmin-on-swiping, but it could be useful to keep in mind for views that do not inherit from UIScrollView // UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)]; // swipeUpGestureRecognizer.cancelsTouchesInView = NO; // swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp; // [self.tableView addGestureRecognizer:swipeUpGestureRecognizer]; UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)]; //this prevents the gestureRecognizer to override other Taps, such as Cell Selection tapGestureRecognizer.cancelsTouchesInView = NO; [self.tableView addGestureRecognizer:tapGestureRecognizer]; }
将tapGestureRecognizer.cancelsTouchesInView设置为NO是为了避免gestureRecognizer覆盖UITableView的正常内部工作方式(例如,不要干扰单元格select)。
最后,为了处理UITableView的上下滚动键盘,我们必须实现UIScrollViewDelegate协议的scrollViewWillBeginDragging:方法,如下所示:
.h文件
@interface MyViewController : UIViewController <UIScrollViewDelegate>
.m文件
#pragma mark - UIScrollViewDelegate -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self hideKeyboard]; }
我希望它有帮助! =)
以下是我最终做出的作品。 我结合不同答案的build议和代码。 特点:解除键盘,移动键盘上方的文本字段,同时编辑和设置“下一步”和“完成”键盘返回types。更多字段的“…”
static const CGFloat ANIMATION_DURATION = 0.4; static const CGFloat LITTLE_SPACE = 5; CGFloat animatedDistance; CGSize keyboardSize; @interface ViewController () <UITextFieldDelegate> @property (weak, nonatomic) IBOutlet UITextField *firstNameTXT; .....// some other text fields @property (weak, nonatomic) IBOutlet UITextField *emailTXT; @end @implementation ViewController - (void)viewDidLoad{ ..... // add tap gesture to help in dismissing keyboard UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)];// outside textfields [self.view addGestureRecognizer:tapGesture]; // set text fields return key type to Next, last text field to Done [self.firstNameTXT setReturnKeyType:UIReturnKeyNext]; ..... [self.emailTXT setReturnKeyType:UIReturnKeyDone]; // set text fields tags [self.firstNameTXT setTag:0]; ....// more text fields [self.emailTXT setTag:5]; // add keyboard notification [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil]; } [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; } // dismiss keyboard when tap outside text fields - (IBAction)tapScreen:(UITapGestureRecognizer *)sender { if([self.firstNameTXT isFirstResponder])[self.firstNameTXT resignFirstResponder]; ... if([self.emailTXT isFirstResponder])[self.emailTXT resignFirstResponder]; } - (BOOL)textFieldShouldReturn:(UITextField *)textField{ if(textField.returnKeyType==UIReturnKeyNext) { // find the text field with next tag UIView *next = [[textField superview] viewWithTag:textField.tag+1]; [next becomeFirstResponder]; } else if (textField.returnKeyType==UIReturnKeyDone || textField.returnKeyType==UIReturnKeyDefault) { [textField resignFirstResponder]; } return YES; } // Moving current text field above keyboard -(BOOL) textFieldShouldBeginEditing:(UITextField*)textField{ CGRect viewFrame = self.view.frame; CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField]; CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view]; CGFloat textFieldBottomLine = textFieldRect.origin.y + textFieldRect.size.height + LITTLE_SPACE;// CGFloat keyboardHeight = keyboardSize.height; BOOL isTextFieldHidden = textFieldBottomLine > (viewRect.size.height - keyboardHeight)? TRUE :FALSE; if (isTextFieldHidden) { animatedDistance = textFieldBottomLine - (viewRect.size.height - keyboardHeight) ; viewFrame.origin.y -= animatedDistance; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView setAnimationDuration:ANIMATION_DURATION]; [self.view setFrame:viewFrame]; [UIView commitAnimations]; } return YES; } -(void) restoreViewFrameOrigionYToZero{ CGRect viewFrame = self.view.frame; if (viewFrame.origin.y != 0) { viewFrame.origin.y = 0; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationBeginsFromCurrentState:YES]; [UIView setAnimationDuration:ANIMATION_DURATION]; [self.view setFrame:viewFrame]; [UIView commitAnimations]; } } -(void)keyboardDidShow:(NSNotification*)aNotification{ NSDictionary* info = [aNotification userInfo]; keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; } -(void)keyboardDidHide:(NSNotification*)aNotification{ [self restoreViewFrameOrigionYToZero];// keyboard is dismissed, restore frame view to its zero origin } @end
@ mixca的答案是非常有用的,但如果我有一些不同于UITextField。 我认为最好的方式来处理它通过search与recursionfunction的主视图的所有子视图,检查下面的例子
- (BOOL)findAndResignFirstResponder { if (self.isFirstResponder) { [self resignFirstResponder]; return YES; } for (UIView *subView in self.subviews) { if ([subView findAndResignFirstResponder]) { return YES; } } return NO; }
也可以把这个方法放到你的实用课堂上,并且可以使用@ mixca的答案。
UITableView
有一个方便的backgroundView
属性,我用它实现了这个行为而不用搞乱单元格select,如下面的Swift所示:
let tableBackTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard)) tableView.backgroundView = UIView() tableView.backgroundView?.addGestureRecognizer(tableBackTapRecognizer)