xcode 获取 UITableView 滚动到选定的 UITextField 并避免被键盘隐藏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5265559/
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
Get UITableView to scroll to the selected UITextField and Avoid Being Hidden by Keyboard
提问by Lauren Quantrell
I have a UITextField
in a table view on a UIViewController
(not a UITableViewController
).
If the table view is on a UITableViewController
, the table will automatically scroll to the textField
being edited to prevent it from being hidden by the keyboard. But on a UIViewController
it does not.
我UITextField
在 a UIViewController
(不是 a UITableViewController
)上有一个表视图。如果表格视图在 上UITableViewController
,表格将自动滚动到textField
正在编辑的位置,以防止它被键盘隐藏。但在 aUIViewController
它没有。
I have tried for a couple of days reading through multiple ways to try to accomplish this and I cannot get it to work. The closest thing that actually scrolls is:
我已经尝试了几天阅读多种方法来尝试实现这一点,但我无法让它发挥作用。实际滚动的最接近的东西是:
-(void) textFieldDidBeginEditing:(UITextField *)textField {
// SUPPOSEDLY Scroll to the current text field
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];
}
However this only scrolls the table to the topmost row. What seems like an easy task has been a couple of days of frustration.
但是,这只会将表格滚动到最上面的行。看似简单的任务却经历了几天的挫折。
I am using the following to construct the tableView cells:
我正在使用以下内容来构建 tableView 单元格:
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:identifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];
theTextField.adjustsFontSizeToFitWidth = YES;
theTextField.textColor = [UIColor redColor];
theTextField.text = [textFieldArray objectAtIndex:indexPath.row];
theTextField.keyboardType = UIKeyboardTypeDefault;
theTextField.returnKeyType = UIReturnKeyDone;
theTextField.font = [UIFont boldSystemFontOfSize:14];
theTextField.backgroundColor = [UIColor whiteColor];
theTextField.autocorrectionType = UITextAutocorrectionTypeNo;
theTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
theTextField.clearsOnBeginEditing = NO;
theTextField.textAlignment = UITextAlignmentLeft;
//theTextField.tag = 0;
theTextField.tag=indexPath.row;
theTextField.delegate = self;
theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
[theTextField setEnabled: YES];
[cell addSubview:theTextField];
[theTextField release];
}
return cell;
}
I suspect I can get the tableView to scroll properly if I can somehow pass the indexPath.row
in the textFieldDidBeginEditing
method?
我怀疑我能得到的tableView到正常滚动,如果我能以某种方式传递indexPath.row
的textFieldDidBeginEditing
方法是什么?
Any help is appreciated.
任何帮助表示赞赏。
回答by Andrei Stanescu
In my app, I have successfully used a combination of contentInset
and scrollToRowAtIndexPath
like this:
在我的应用程序中,我成功地使用了contentInset
和scrollToRowAtIndexPath
这样的组合:
When you want to display the keyboard, just add a contentInset at the bottom with your table with desired height:
当您想显示键盘时,只需在表格底部添加一个具有所需高度的 contentInset :
tableView.contentInset = UIEdgeInsetsMake(0, 0, height, 0);
Then, you can safely use
然后,您可以安全地使用
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:cell_index inSection:cell_section] animated:YES];
By adding the contentInset, even if you are focusing on the last cell the tableView will still be able to scroll. Just make sure that when you are dismissing the keyboard, you reset the contentInset.
通过添加 contentInset,即使您专注于最后一个单元格,tableView 仍然能够滚动。只需确保在关闭键盘时重置 contentInset。
EDIT:
If you have only one section (you can replace cell_section
with 0) and the use the textView tag to inform the cell row.
编辑:
如果您只有一个部分(您可以cell_section
用 0替换)并且使用 textView 标记来通知单元格行。
回答by FunkyKat
- (void)keyboardWillShow:(NSNotification *)sender
{
CGFloat height = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 0, height, 0);
tableView.contentInset = edgeInsets;
tableView.scrollIndicatorInsets = edgeInsets;
} completion:nil];
}
- (void)keyboardWillHide:(NSNotification *)sender
{
NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{
UIEdgeInsets edgeInsets = UIEdgeInsetsZero;
tableView.contentInset = edgeInsets;
tableView.scrollIndicatorInsets = edgeInsets;
} completion:nil];
}
And in - (void)viewDidLoad
而在 - (void)viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
Then
然后
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
回答by bmauter
This is a tweak to FunkyKat's answer (big thank you FunkyKat!). It would probably be beneficial to not hardcode UIEdgeInsetsZero for future iOS compatibility.
这是对 FunkyKat 答案的调整(非常感谢 FunkyKat!)。为了将来的 iOS 兼容性,不硬编码 UIEdgeInsetsZero 可能是有益的。
Instead, I ask for the current inset value and tweak the bottom value as needed.
相反,我要求当前插入值并根据需要调整底部值。
- (void)keyboardWillShow:(NSNotification *)sender {
CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.height : kbSize.width;
if (isIOS8()) height = kbSize.height;
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = [[self tableView] contentInset];
edgeInsets.bottom = height;
[[self tableView] setContentInset:edgeInsets];
edgeInsets = [[self tableView] scrollIndicatorInsets];
edgeInsets.bottom = height;
[[self tableView] setScrollIndicatorInsets:edgeInsets];
}];
}
- (void)keyboardWillHide:(NSNotification *)sender {
NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
UIEdgeInsets edgeInsets = [[self tableView] contentInset];
edgeInsets.bottom = 0;
[[self tableView] setContentInset:edgeInsets];
edgeInsets = [[self tableView] scrollIndicatorInsets];
edgeInsets.bottom = 0;
[[self tableView] setScrollIndicatorInsets:edgeInsets];
}];
}
回答by Lauren Quantrell
For the sake of anyone else running into this issue, I'm posting the necessary methods here:
为了其他人遇到这个问题,我在这里发布了必要的方法:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]];
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)];
theTextField.keyboardType = UIKeyboardTypeDefault;
theTextField.returnKeyType = UIReturnKeyDone;
theTextField.clearsOnBeginEditing = NO;
theTextField.textAlignment = UITextAlignmentLeft;
// (The tag by indexPath.row is the critical part to identifying the appropriate
// row in textFieldDidBeginEditing and textFieldShouldEndEditing below:)
theTextField.tag=indexPath.row;
theTextField.delegate = self;
theTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
[theTextField setEnabled: YES];
[cell addSubview:theTextField];
[theTextField release];
}
return cell;
}
-(void) textFieldDidBeginEditing:(UITextField *)textField {
int z = textField.tag;
if (z > 4) {
// Only deal with the table row if the row index is 5
// or greater since the first five rows are already
// visible above the keyboard
// resize the UITableView to fit above the keyboard
self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,200.0);
// adjust the contentInset
wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10);
// Scroll to the current text field
[wordsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:z inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
// Determine which row is being edited
int z = textField.tag;
if (z > 4) {
// resize the UITableView to the original size
self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,416.0);
// Undo the contentInset
wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// Dismisses the keyboard when the "Done" button is clicked
[textField resignFirstResponder];
return YES;
}
回答by vinothsivanandam
Try my coding, this will help for ypu
试试我的编码,这对 ypu 有帮助
tabelview.contentInset = UIEdgeInsetsMake(0, 0, 210, 0);
[tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:your_indexnumber inSection:Your_section]
atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
回答by Salman Hasrat Khan
Apple has an official post explaining how to do this naturally as they do in the UITableViewController. My Stackoverflow answer has this explained along with a swift version.
Apple 有一篇官方文章解释了如何像在 UITableViewController 中那样自然地做到这一点。我的 Stackoverflow 答案对此进行了解释,并附有一个 swift 版本。
回答by Nik Kov
I needed a simple solution so for me helped:
我需要一个简单的解决方案,所以对我有帮助:
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
let pointInTable = textField.superview!.convert(textField.frame.origin, to: tableView)
var tableVContentOffset = tableView.contentOffset
tableVContentOffset.y = pointInTable.y
if let accessoryView = textField.inputAccessoryView {
tableVContentOffset.y -= accessoryView.frame.size.height
}
tableView.setContentOffset(tableVContentOffset, animated: true)
return true;
}
回答by Vadim Shevchik
My code. Maybe someone will be useful: Custom textField cell in tableView
我的代码。也许有人会很有用:tableView 中的自定义 textField 单元格
.m
.m
@property (nonatomic, strong) UITextField *currentCellTextField;
CustomCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
cell = (CustomCell *)[nib objectAtIndex:0];
cell.textfield.delegate = self;
}
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
self.currentCellTextField = textField;
CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];
if (path.section >= 2) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.organisationTableView.contentInset = UIEdgeInsetsMake(0, 0, kOFFSET_FOR_KEYBOARD, 0);
CGPoint siize = self.organisationTableView.contentOffset;
siize.y =(pnt.y-170);
self.organisationTableView.contentOffset = CGPointMake(0, siize.y);
[UIView commitAnimations];
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField];
NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt];
if (path.section >= 2) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.organisationTableView.contentInset = UIEdgeInsetsZero;
self.organisationTableView.contentOffset = CGPointMake(0, self.organisationTableView.contentOffset.y);
[UIView commitAnimations];
}
return YES;
}
回答by GendoIkari
You need to resize the tableView itself so that it does not go under the keyboard.
您需要调整 tableView 本身的大小,使其不会在键盘下方。
-(void) textFieldDidBeginEditing:(UITextField *)textField {
// SUPPOSEDLY Scroll to the current text field
self.worldsTableView.frame = CGRectMake(//make the tableView smaller; to only be in the area above the keyboard);
CGRect textFieldRect = [textField frame];
[self.wordsTableView scrollRectToVisible:textFieldRect animated:YES];
}
Alternatively, you can use a keyboard notification; this works slightly better because you have more information, and is more consistent in terms of knowing when the keyboard is coming up:
或者,您可以使用键盘通知;这稍微好一点,因为您有更多信息,并且在知道键盘何时出现方面更加一致:
//ViewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
And then implement:
然后执行:
- (void)keyboardWillShow:(NSNotification *)notification {
}
- (void)keyboardWillHide:(NSNotification *)notification {
}
回答by Mike.R
In my case my UITableview was inside another UIView and that UIvie was in the main UIScrollview. So I used more general solution for those kind of problems. I simply found the Y coordinate of my cell in the specific UIScrollView and then scrolled to correct point:
在我的情况下,我的 UITableview 在另一个 UIView 中,而 UIvie 在主 UIScrollview 中。所以我对这些问题使用了更通用的解决方案。我只是在特定的 UIScrollView 中找到了我的单元格的 Y 坐标,然后滚动到正确的点:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
float kbHeight = 216;//Hard Coded and will not support lanscape mode
UITableViewCell *cell = (UITableViewCell *)[textField superview];
float scrollToHeight = [self FindCordinate:cell];
[(UIScrollView *)self.view setContentOffset:CGPointMake(0, scrollToHeight - kbHeight + cell.frame.size.height) animated:YES];
}
-(float)FindCordinate:(UIView *)cell{
float Ycordinate = 0.0;
while ([cell superview] != self.view) {
Ycordinate += cell.frame.origin.y;
cell = [cell superview];
}
Ycordinate += cell.frame.origin.y;
return Ycordinate;
}