objective-c 单击 UITableViewCell 中的 UITextField
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/350868/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Clicking on UITextField in a UITableViewCell
提问by Coocoo4Cocoa
I have an issue where when a textFieldis clicked on in a UITableViewCell, the method tableView:didSelectRowAtIndexPath:does not get invoked. The problem is, I need to scroll my tableViewinto proper position, otherwise the keyboard goes right over the first responder.
我有一个问题,当在 atextField中单击 a 时UITableViewCell,该方法tableView:didSelectRowAtIndexPath:不会被调用。问题是,我需要将我的滚动tableView到正确的位置,否则键盘会直接越过第一响应者。
I have to then move code like this:
然后我必须像这样移动代码:
[[self tableView] scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
into both my tableViewdelegate method and in my UITextFielddelegate method, textFieldDidBeginEditing:.
进入我的tableView委托方法和我的UITextField委托方法,textFieldDidBeginEditing:.
Is the best way to just create a new method, pass to it the indexPath of the cell/textfield being clicked, and call the method from both the tableView delegate and the UITextFielddelegate? better way of going about it?
是创建一个新方法、将单击的单元格/文本字段的 indexPath 传递给它并从 tableView 委托和UITextField委托调用该方法的最佳方法吗?更好的方法是什么?
回答by Friggles
I found the following works well (It assumes you're in a table view controller)
我发现以下效果很好(假设您在表视图控制器中)
- (void)textFieldDidBeginEditing:(UITextField *)textField{
CGPoint pnt = [self.tableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.tableView indexPathForRowAtPoint:pnt];
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
回答by Coocoo4Cocoa
There are a couple of ways to fix this issue. What happens is that the tableViewCell delegates the touch event to its subviews which causes the textfield to handle the touch in stead of your cell.
有几种方法可以解决此问题。发生的情况是 tableViewCell 将触摸事件委托给它的子视图,这会导致文本字段而不是您的单元格处理触摸。
To fix this:
要解决此问题:
Set the UITextfield's userinteractionEnabled property to NO, then when you get the didSelectRowAtIndexPath message you re-enable userInteractionEnabled and call the TextField's becomeFirstResponder. On v2.2 you don't even need to set the userInteractionEnabled flag, I have not tested this with other versions however the documentation is quite clear that you should have this enabled. in the tableViewController you simply need to have the indexpath saved until you get the UIKeyboardDidShow message
Create a delegate for the UITextField that reports back to your tableViewController so that you can set the scrolling offset from there.
register for the keyboard events and then figure out the scrolloffset by checking what textfield is in editing mode
将 UITextfield 的 userinteractionEnabled 属性设置为 NO,然后当您收到 didSelectRowAtIndexPath 消息时,您重新启用 userInteractionEnabled 并调用 TextField 的 becomeFirstResponder。在 v2.2 上,您甚至不需要设置 userInteractionEnabled 标志,我还没有用其他版本对此进行过测试,但是文档很清楚您应该启用它。在 tableViewController 中,您只需要保存索引路径,直到收到 UIKeyboardDidShow 消息
为 UITextField 创建一个向您的 tableViewController 报告的委托,以便您可以从那里设置滚动偏移量。
注册键盘事件,然后通过检查处于编辑模式的文本字段来确定滚动偏移
回答by August
You can set your controller as the delegate of your UITextField, then adjust your table view in either textFieldDidBeginEditing:or textFieldShouldBeginEditing:
您可以将控制器设置为 UITextField 的委托,然后在textFieldDidBeginEditing:或textFieldShouldBeginEditing:
回答by Wayne Lo
I did not find any solutions that work for me in the web. After days of Googling and experimenting, I finally have this issued well nailed. It is a complex bug in Apple iPhone as you will see in the end of this post.
我在网络上没有找到任何适合我的解决方案。经过几天的谷歌搜索和试验,我终于把这个问题搞定了。正如您将在本文末尾看到的,这是 Apple iPhone 中的一个复杂错误。
If you ran into an issue like me as follows:
如果您遇到像我这样的问题,如下所示:
having tableviewcell larger than half of the iphone screen (Do not confused with Apple's UICatalog's examples have a short tableview cell of less than 50 points, not applicable here.),
having more than one uitexfields in the cell or combination of uitextfield and uitextview or uiwebview in the cell,
Tapping between uitextfields and uitextview or uiwebview results in unpredictable scroll position either the clicked uitextfield jumps out of view or covered by the keybaord. It only works the very first time when the keyboard appears in the tableviewcell and not working right subsequently.
使 tableviewcell 大于 iPhone 屏幕的一半(不要与 Apple 的 UICatalog 示例混淆,tableview cell 小于 50 点,此处不适用。),
单元格中有多个 uitexfields 或单元格中有 uitextfield 和 uitextview 或 uiwebview 的组合,
在 uitextfields 和 uitextview 或 uiwebview 之间轻敲会导致不可预测的滚动位置,要么单击的 uitextfield 跳出视图,要么被键盘覆盖。它仅在第一次键盘出现在 tableviewcell 中时才有效,随后无法正常工作。
I had the major break through after reading posts similar to this one: http://alanduncan.net/old/index.php?q=node/13They did not get it completely right either. The pain is caused by a bug in UIKeyboard events. When the keyboard first appear, it issue an UIKeyboardWillShowNotification and UIKeybaordDidShowNotification. Theree is a bug in iPhone that somehow the first UIKeyboardWillShowNotification differs from the subsequent UIKeyboardWillShowNotification. The solution is to OBSERVE UIKeyboardDidShowNotification. So when your cell will appear, add the following code
在阅读了与以下类似的帖子后,我有了重大突破:http: //alanduncan.net/old/index.php?q=node/13他们也没有完全正确。痛苦是由 UIKeyboard 事件中的错误引起的。当键盘第一次出现时,它会发出 UIKeyboardWillShowNotification 和 UIKeybaordDidShowNotification。iPhone 中存在一个错误,即第一个 UIKeyboardWillShowNotification 与随后的 UIKeyboardWillShowNotification 不同。解决方案是观察 UIKeyboardDidShowNotification。所以当你的单元格出现时,添加以下代码
NSNotificationCenter*nc=[NSNotificationCenter defaultCenter];
[nc addObserver:self selectorselector(keyboardDidShow name:UIKeyboardDidShowNotification object:self.window];
In the keyboardDidShow function, we need to scroll the TABLEVIEW, not the tableviewcell as suggested in above post. Or you may see various objects go separate way, not scroll together in one piece.
在keyboardDidShow函数中,我们需要滚动TABLEVIEW,而不是上面帖子中建议的tableviewcell。或者您可能会看到各种对象分开运行,而不是一起滚动。
(void)keyboardDidShow:(NSNotification *)notif
{
//1. see which field is calling the keyboard
CGRect frame;
if([textField_no1 isFirstResponder])
frame=textField_no1.frame;
else if([textField_no2 isFirstResponder])
frame=textField_no2.frame;
else if([textField_no3 isFirstResponder])
frame=textField_no3.frame;
else if([textView isFirstResponder])
frame=textView.frame;
else return;
CGRect rect=self.superview.frame;
//2. figure out how many pixles to scroll up or down to the posistion set by theKeyBoardShowUpHorizon.
//remove the complexity when the tableview has an offset
[((UITableView*)[self.superview).setContentOffset:CGPointMake(0,0) animated:YES];
int pixelsToMove=rect.origin.y+ frame.origin.y-theKeyBoardShowUpHorizon;
//3. move the uitableview, not uitableviewcell
[self moveViewUpOrDownByPixels:pixelsToMove];
}
- (void)moveViewUpOrDownByPixels:(int)pixels
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.6];
//find the position of the UITableView, the superView of this tableview cell.
CGRect rect=self.superview.frame;
//moves tableview up (when pixels >0) or down (when pixels <0)
rect.origin.y -= pixels;
rect.size.height += pixels;
self.superview.frame = rect;
[UIView commitAnimations];
}
To restore the tableView back, you need to add observer on UIKeyboardDidHideNotification (not UIKeyboardWillHideNotification as suggested by other posts, to avoid flickering) where you tableviewcell appears every time and put back the tableview to where it was.
要恢复 tableView,您需要在 UIKeyboardDidHideNotification(不是其他帖子建议的 UIKeyboardWillHideNotification,以避免闪烁)上添加观察者,每次都会出现 tableviewcell 并将 tableview 放回原来的位置。
[nc addObserver:self selectorselector(keyboarDidHide) name:UIKeyboardDidHideNotification object:nil];
- (void)keyboardDidHideNSNotification*)notif
{
//we have moved the tableview by number of pixels reflected in (self.superview.frame.origin.y). We need to move it back
[self moveViewUpOrDownByPixels:self.superview.frame.origin.y];
}
Do not forget to remove both of the observesr when your cell disappear by [[NSNotificationCenter defaultCenter] removeObserver:...
当您的单元格消失时,不要忘记删除两个观察者 [[NSNotificationCenter defaultCenter] removeObserver:...
That is all it takes. I hope Apple iPhone team one day will resolve this issue, maybe in 4.0 in a few months.
这就是全部。我希望苹果 iPhone 团队有朝一日能解决这个问题,也许几个月后会在 4.0 中解决。
回答by Andi
I've found a solution.
我找到了解决办法。
- Open .xib file in interface builder.
- Select the table view
- From IB Menu select Tools->Size Inspector On Scroll View Size Section, modify Inset -> Bottom valueto 100, 150 ,250 depending how big is your table view.
- 在界面生成器中打开 .xib 文件。
- 选择表格视图
- 从 IB 菜单中选择 Tools->Size Inspector On Scroll View Size Section,将Inset -> Bottom 值修改为100、150、250,具体取决于您的表格视图有多大。
Code
代码
-(void) textFieldDidBeginEditing:(UITextField *)textField
{
UITableViewCell *cell = (UITableViewCell *) [[textField superview] superview];
[self.tableView scrollToRowAtIndexPath:[tableView indexPathForCell:cell]
atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
回答by Michael
I discovered that it's actually pretty easy to do this.
我发现实际上很容易做到这一点。
The UITextField delegate method textFieldDidBeginEditing will give you the text field, which you can then map to an indexPath using:
UITextField 委托方法 textFieldDidBeginEditing 将为您提供文本字段,然后您可以使用以下方法将其映射到 indexPath:
self.currentIndexPath = [self.tableView indexPathForRowAtPoint:textField.frame.origin];
Then you can scroll the cell into view (i.e. in your UIKeyboardDidShowNotification keyboard notification handler):
然后您可以将单元格滚动到视图中(即在您的 UIKeyboardDidShowNotification 键盘通知处理程序中):
[self.tableView scrollToRowAtIndexPath:self.currentIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
回答by Ramesh
didSelectRowAtIndexPath won't be called for UITextField embedded cells; hence, scroll logic needs to be elsewhere.
不会为 UITextField 嵌入单元调用 didSelectRowAtIndexPath;因此,滚动逻辑需要在别处。
- (void)textFieldDidBeginEditing:(UITextField *)textField {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:1];
UITableViewCell *cell = [_tableView cellForRowAtIndexPath:indexPath];
[_tableView setContentOffset:CGPointMake(0, cell.frame.size.height) animated:YES];
}
Make sure to wire textField delegate to self
确保将 textField 委托连接到 self
回答by Ben Sinclair
The problem is aggravated by the fact that there is no simple way to find out whether user tapped on text field or it was activated via becomeFirstResponder.
由于没有简单的方法可以确定用户是点击了文本字段还是通过becomeFirstResponder.
The most elegant solution I could come up with was to implement a hitTest:withEvent:on cell subclass and basically pretend that text field does not exist until cell is selected.
我能想出的最优雅的解决方案是实现一个hitTest:withEvent:on cell 子类,并且基本上假装在选择单元格之前文本字段不存在。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [super hitTest:point withEvent:event];
if(view == self.textField && !self.selected) {
return self;
}
return view;
}
tableView:didSelectRowAtIndexPath:then should manually make text field a first responder.
tableView:didSelectRowAtIndexPath:然后应该手动使文本字段成为第一响应者。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TextFieldCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell.textField becomeFirstResponder]
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
Finally, we have to deselect the row when we finish editing. This can be done via UITextField delegate or via keyboard notification, whatever you prefer.
最后,我们必须在完成编辑后取消选择该行。这可以通过 UITextField 委托或通过键盘通知来完成,无论您喜欢什么。
- (void)textFieldDidEndEditing:(UITextField *)textField {
[self.view endEditing:YES];
}
回答by Narayana
we have one controller called TPKeyboardAvoiding, it handled everything about dynamic auto scrolling for tableview and scrollview. you can download sample code from below code. https://github.com/NarayanaRao35/TPKeyboardAvoiding
我们有一个名为TPKeyboardAvoiding 的控制器,它处理有关 tableview 和 scrollview 的动态自动滚动的所有内容。您可以从下面的代码下载示例代码。 https://github.com/NarayanaRao35/TPKeyboardAvoiding
回答by Brandon Fosdick
Register for UIKeyboardWillShowNotification and UIKeyboardWillHideNotification, then adjust your view as necessary in the notification handlers. One of the example apps shows how to do this, but I forget which...SQLiteBooks, or maybe EditableDetailView.
注册 UIKeyboardWillShowNotification 和 UIKeyboardWillHideNotification,然后根据需要在通知处理程序中调整您的视图。示例应用程序之一展示了如何执行此操作,但我忘记了哪个...SQLiteBooks,或者 EditableDetailView。

