我有一个UITableView
以UITextField
s作为单元格。我想在UITableView
触摸的背景时关闭键盘。我正在尝试通过创建UIButton
的大小UITableView
并将其放在的后面来实现此目的UITableView
。唯一的问题是,UIButton
即使触摸在UITableView上,也要捕获所有触摸。我究竟做错了什么?
谢谢!
我有一个UITableView
以UITextField
s作为单元格。我想在UITableView
触摸的背景时关闭键盘。我正在尝试通过创建UIButton
的大小UITableView
并将其放在的后面来实现此目的UITableView
。唯一的问题是,UIButton
即使触摸在UITableView上,也要捕获所有触摸。我究竟做错了什么?
谢谢!
Answers:
可以通过创建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
内部单元格等上触发它。
gestureRecognizer.cancelsTouchesInView = NO;
hideKeyboard
方法,您可以执行,而不是直接与文本字段进行通信[self.view endEditing:NO];
。从Apple文档中:“ 该方法查看当前视图和它的子视图层次结构中当前是第一响应者的文本字段。如果找到该文本字段,则要求该文本字段辞去第一响应者的角色。如果force参数设置为是的,从未询问过该文本字段;它被迫辞职。 ”
如果您进行以下设置,则UITapGestureRecognizer解决方案可用于表格单元格选择:
gestureRecognizer.cancelsTouchesInView = NO;
shouldReceiveTouch
作为UITableView
的子类UIScrollView
,实现下面的一个委托方法提供了一种极其简单,快速的解决方案。resignFirstResponder
由于视图层次结构会进行自省并找到当前响应者,并要求其退出响应者状态,因此甚至无需参与。
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.view endEditing:YES];
}
并记住要添加UIScrollViewDelegate
到头文件。
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag
首先,通过添加来收听scrollViewWillBeginDragging
您UIViewController
的声音UIScrollViewDelegate
:
在.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];
}
并且,如果像我一样,您想要关闭自定义表格单元格内的UITextField的键盘,请执行以下操作:
- (void)dismissKeyboard {
NSLog(@"dismissKeyboard");
CustomCellClass *customCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
[customCell.textFieldInCell resignFirstResponder];
}
希望对任何人有帮助!!
这是您的编码乐趣的快速版本:
它添加了轻击手势识别器,然后关闭了键盘。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
}
有Swift 3版本,没有阻止单元格上的点击。
在viewDidLoad()
方法中:
let dismissKeyboardGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
dismissKeyboardGesture.cancelsTouchesInView = false
tableView.addGestureRecognizer(dismissKeyboardGesture)
而且hideKeyboard
是这样的:
func hideKeyboard() {
view.endEditing(true)
}
我这样做是这样的:
在TableViewController中创建一个方法以停用第一个响应者(此时将是您的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];
...
}
didSelectRowAtIndexPath
不,如果你挖掘的TableView本身火灾。
我有一个UITableViewController
,实施touchesBegan:withEvent:
对我没有用。
这是起作用的:
迅速:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
view.endEditing(true)
}
目标C:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.view endEditing:YES];
}
@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的类型设置为DismissableUITableView .....也许我可以想到此类的更好名称,但是您明白了。
如果您的目标是iOS7,则可以使用以下之一:
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
滚动表视图时,前者将在屏幕外为键盘动画,而后者将像股票Messages应用一样隐藏键盘。
请注意,这些都是UIScrollView
,这UITableView
从继承。
试试这个:
viewDidLoad(){
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
tableView.addGestureRecognizer(tap)
}
//Calls this function when the tap is recognized.
@objc func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
UITableView是UIScrollView的子类。
我这样做的方法是侦听用户的滚动事件,然后重新签名resignFirstResponder。这是在代码中实现的UIScrollViewDelegate方法;
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
解决这类问题时,我发现最好的方法是研究每个对象和父类的委托协议(在这种情况下,UITableViewDelegate,UIScrollViewDelegate。NS对象触发的事件数量非常大而且很全面。还可以轻松实现协议,然后再将其子类化。
我遇到了同样的问题,这是我的解决方案,它对我来说非常有效:
在您实现的视图或视图控制器中 <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];
希望能帮助到你。
我希望我的单元格在选择单元格的任何部分时都可以打开键盘,并在单击该单元格的任何位置时将其关闭。要打开键盘:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if (selected)
{
[self.textField becomeFirstResponder];
}
}
(注:我子类细胞,但你可以很容易地在实现这一目标tableView:didSelectRowAtIndexPath:
的委托方法UITableView
)
这样做意味着在最佳解决方案中,如果您两次单击该单元格,键盘都会摇晃,首先是手势识别器尝试关闭键盘,然后重新选择该单元格并尝试打开键盘。
解决方案是检查单击是否发生在当前选定的单元格内:
- (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];
}
}
我找到了一个很好的解决方案。
需要使用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类中执行的触摸。该hideKeyboard方法只有当触摸已经UITableViewCell类,外执行将被调用。
- (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];
}
UITableView
具有一个方便的backgroundView
属性,通过它我可以实现此行为而不会影响单元格选择,如以下Swift中所示:
let tableBackTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
tableView.backgroundView = UIView()
tableView.backgroundView?.addGestureRecognizer(tableBackTapRecognizer)
我正在寻找解决方案,但找不到适合我的代码的任何东西,所以我这样做是这样的:
http://82517.tumblr.com/post/13189719252/dismiss-keyboard-on-uitableview-non-cell-tap
它基本上是前面提到的方法的组合,但是不需要子类化或创建背景按钮。
只需使用UITapGestureRecognizer并cancelsTouchesInView = NO
意味着点击单元格和UITextViews也会触发隐藏。如果您有多个UITextView,然后单击下一个,则这很不好。键盘将开始隐藏,然后下一个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];
}
为什么要创建一个充满文本字段的表?您应该为包含文本字段的每一行使用详细视图。按下详细视图时,请确保调用“ [myTextField成为FirstResponder]”,以便用户只需单击表列表即可一开始进行编辑。
如果你愿意的子类(啊!)你的表视图,这样的事情可能工作:
- (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];
}
如果要在按下返回键的同时关闭键盘,则只需在textField应该返回方法中添加以下代码即可:
- (BOOL)textFieldShouldReturn:(UITextField *)atextField
{
[textField resignFirstresponder];
}
某些文本字段可能具有选择器视图,而某些其他视图可能具有子视图,因此在这种情况下,上述方法不起作用,因此在这种情况下,我们需要使用UITapGestureRecognizer类,即在viewDidLoad方法中添加以下代码段,即:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
现在,只需将辞职响应者添加到选择器方法中,即:
-(void)dismissKeyboard
{
[textField resignFirstResponder];
}
希望能有所帮助,谢谢:)
许多有趣的答案。我想在我认为最适合UITableView方案的解决方案中使用不同的方法(这是我通常使用的方案):通常,我们通常希望在两种情况下隐藏键盘:在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进行辞职,因此比独立地对每个元素进行辞职更实用。
接下来,我们将通过外部的Tap手势来消除,具体如下:
- (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的正常内部工作(例如,不干扰单元格选择)。
最后,要在向上/向下滚动UITableView时隐藏键盘,我们必须实现UIScrollViewDelegate协议scrollViewWillBeginDragging:方法,如下所示:
.h文件
@interface MyViewController : UIViewController <UIScrollViewDelegate>
.m文件
#pragma mark - UIScrollViewDelegate
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self hideKeyboard];
}
希望对您有所帮助!=)
这就是我最终制作作品的方式。我结合了来自不同答案的建议和代码。功能:消除键盘,在编辑和设置“下一步”和“完成”键盘返回类型时移动键盘上方的文本字段。替换带有更多字段的“ ...”
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不同,该怎么办。我认为最好的方法是通过使用递归函数搜索主视图的所有子视图,请检查以下示例
- (BOOL)findAndResignFirstResponder {
if (self.isFirstResponder) {
[self resignFirstResponder];
return YES;
}
for (UIView *subView in self.subviews) {
if ([subView findAndResignFirstResponder]) {
return YES;
}
}
return NO;
}
并且您也可以将此方法放入实用程序类,并可以使用@mixca的答案之类的点击手势。