选择文本字段时,使UITableView滚动

247 iphone keyboard scroll uitableview ios

经过大量的反复试验,我放弃并提出问题.我见过很多人有类似的问题,但无法得到所有正确的答案.

我有一个UITableView由自定义单元格组成的.单元格由5个文本字段组成,彼此相邻(有点像网格).

当我尝试滚动并编辑底部的单元格时UITableView,我无法将单元格正确放置在键盘上方.

我已经看到很多关于改变视图大小的答案......但到目前为止它们都没有很好地工作.

任何人都可以用具体的代码示例澄清"正确"的方法吗?

Sam*_* Ho 125

如果您使用UITableViewController而不是UIViewController,它将自动执行此操作.

  • 如果覆盖[super viewWillAppear:YES],它将无法工作.除此之外,它应该工作. (32认同)
  • 如果覆盖viewWillAppear:(BOOL)动画,请不要忘记调用[super viewWillAppear:animated]; :) (18认同)
  • 你试过,发现不工作了吗?或者解决方案太简单了吗?只需扩展UITableViewController而不是UIViewController,只要文本字段成为第一个响应者,包含文本字段的单元格就会在键盘上方滚动.无需额外代码. (13认同)
  • 要澄清一下,说每次使用tableview都需要全屏显示,这不是一个合理的答案,特别是在iPad上.有很多很棒的应用程序没有这样做的例子.例如,许多Apple自己的,包括iPad上的Contacts应用程序. (13认同)
  • 是的,但特别是在iPad上,我们需要一种不涉及UITableViewController的方法. (3认同)
  • 在100%的时间不起作用.我有自动滚动工作,现在突然它拒绝工作...... (2认同)
  • 我也有这个问题.它过去自动工作,但现在不:( (2认同)

小智 92

滚动的功能可以更简单:

- (void) textFieldDidBeginEditing:(UITextField *)textField {
    UITableViewCell *cell;

    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
        cell = (UITableViewCell *) textField.superview.superview;

    } else {
        // Load resources for iOS 7 or later
        cell = (UITableViewCell *) textField.superview.superview.superview; 
       // TextField -> UITableVieCellContentView -> (in iOS 7!)ScrollView -> Cell!
    }
    [tView scrollToRowAtIndexPath:[tView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
Run Code Online (Sandbox Code Playgroud)

而已.根本没有计算.

  • 不适用于表视图的最后几行.键盘仍然会遮挡无法在键盘上方滚动的所有行. (15认同)
  • 通过对superview的一系列调用进入单元格是不可靠的,除非你确定你实际上是进入单元格.请参阅http://stackoverflow.com/a/17757851/1371070和http://stackoverflow.com/a/17758021/1371070 (9认同)
  • 如果UITableViewController在显示键盘时已经处理了表格视图的大小调整,似乎无法工作:控制器使用`contentInset`减小了可见大小,当询问`visibleRows`或`时,它显然没有被考虑在内. indexPathsForVisibleRows`. (3认同)
  • 要使自动滚动行为在表的最后几行上起作用,请检测这些行何时开始编辑,并使用特定高度的空白视图将页脚添加到tableview的末尾.这将允许tableview将单元格滚动到正确的位置. (3认同)
  • 那么为何不?!只需用UITableViewScrollPositionMiddle替换UITableViewScrollPositionTop即可.当然,您只需要重新缩放UITableView以调整可见区域. (2认同)
  • 不要为superview的深度潜水,而是创建一个`UITextField`的子类并获取你的单元格类型的属性`UITableViewCell`.引用单元格到textfield(可能在`tableview:cellForRowAtIndexPath:`方法中).你可以在这里使用它,像这样,`[tView scrollToRowAtIndexPath:[tView indexPathForCell:textfield.cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];` (2认同)

小智 69

我正在做一些非常类似的通用,不需要为你的代码计算特定的东西.只需查看代码上的备注:

在MyUIViewController.h中

@interface MyUIViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
{
     UITableView *myTableView;
     UITextField *actifText;
}

@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet UITextField *actifText;

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField;
- (IBAction)textFieldDidEndEditing:(UITextField *)textField;

-(void) keyboardWillHide:(NSNotification *)note;
-(void) keyboardWillShow:(NSNotification *)note;

@end
Run Code Online (Sandbox Code Playgroud)

在MyUIViewController.m中

@implementation MyUIViewController

@synthesize myTableView;
@synthesize actifText;

- (void)viewDidLoad 
{
    // Register notification when the keyboard will be show
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillShow:)
                                          name:UIKeyboardWillShowNotification
                                          object:nil];

    // Register notification when the keyboard will be hide
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillHide:)
                                          name:UIKeyboardWillHideNotification
                                          object:nil];
}

// To be link with your TextField event "Editing Did Begin"
//  memoryze the current TextField
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.actifText = textField;
}

// To be link with your TextField event "Editing Did End"
//  release current TextField
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.actifText = nil;
}

-(void) keyboardWillShow:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    // Start animation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Reduce size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height -= keyboardBounds.size.height;
    else 
        frame.size.height -= keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    // Scroll the table view to see the TextField just above the keyboard
    if (self.actifText)
      {
        CGRect textFieldRect = [self.myTableView convertRect:self.actifText.bounds fromView:self.actifText];
        [self.myTableView scrollRectToVisible:textFieldRect animated:NO];
      }

    [UIView commitAnimations];
}

-(void) keyboardWillHide:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Increase size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height += keyboardBounds.size.height;
    else 
        frame.size.height += keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    [UIView commitAnimations];
}

@end
Run Code Online (Sandbox Code Playgroud)

Swift 1.2+版本:

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var activeText: UITextField!
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillShow:"),
            name: UIKeyboardWillShowNotification,
            object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillHide:"),
            name: UIKeyboardWillHideNotification,
            object: nil)
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        activeText = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeText = nil
    }

    func keyboardWillShow(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height -= keyboardSize.height
            tableView.frame = frame
            if activeText != nil {
                let rect = tableView.convertRect(activeText.bounds, fromView: activeText)
                tableView.scrollRectToVisible(rect, animated: false)
            }
            UIView.commitAnimations()
        }
    }

    func keyboardWillHide(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height += keyboardSize.height
            tableView.frame = frame
            UIView.commitAnimations()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是我认为最好的答案.很干净.只有两件事:1)你的viewDidLoad没有调用[super viewDidLoad]和2)我必须在frame.size.height行的某些tabbar数学中.否则完美!谢谢. (7认同)
  • 以下是修改toxaq描述:`MyAppDelegate*appDelegate =(MyAppDelegate*)[[UIApplication sharedApplication] delegate]; CGFloat tabBarHeight = appDelegate.tabBarController.tabBar.frame.size.height;`然后在键盘高度的任何位置从键盘高度减去tabBarHeight. (3认同)

ph.*_*dev 44

我有同样的问题,但注意到它只出现在一个视图中.所以我开始寻找控制器的差异.

我发现滚动行为是在- (void)viewWillAppear:(BOOL)animated超级实例中设置的.

所以一定要这样实现:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // your code
}
Run Code Online (Sandbox Code Playgroud)

如果你使用UIViewController或者无关紧要UITableViewController; 通过将a UITableView作为self.view的子视图进行检查UIViewController.这是相同的行为.如果呼叫[super viewWillAppear:animated];丢失,视图不允许滚动.

  • 我也有这个问题,这个答案应该让它达到顶峰! (5认同)

squ*_*022 44

基于BartłomiejSemańczyk解决方案的Swift 3最简单的解决方案:

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

// MARK: Keyboard Notifications

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.2, animations: {
        // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
        self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    })
}
Run Code Online (Sandbox Code Playgroud)


mic*_*ckm 40

我可能错过了这个,因为我没有在这里阅读整篇文章,但我想出的似乎看似简单.我没有通过绞拧器,在所有情况下测试,但它似乎应该工作得很好.

只需通过键盘的高度调整tableview的contentInset,然后将单元格滚动到底部:

- (void)keyboardWasShown:(NSNotification *)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    self.myTableView.contentInset = contentInsets;
    self.myTableView.scrollIndicatorInsets = contentInsets;

    [self.myTableView scrollToRowAtIndexPath:self.currentField.indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
Run Code Online (Sandbox Code Playgroud)

而且当然

- (void)keyboardWasHidden:(NSNotification *)aNotification
{
    [UIView animateWithDuration:.3 animations:^(void) 
    {
        self.myTableView.contentInset = UIEdgeInsetsZero;
        self.myTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
    }];
}
Run Code Online (Sandbox Code Playgroud)

这太简单了吗?我错过了什么吗?到目前为止它对我来说很好,但正如我所说,我还没有通过绞尽脑汁......


Mic*_*aks 35

我想我已经提出了与Apple应用程序行为相匹配的解决方案.

首先,在你的viewWillAppear中:订阅键盘通知,这样你就知道键盘何时显示和隐藏,系统会告诉你键盘的大小,但不要忘记在你的viewWillDisappear中取消注册:.

[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillShow:)
           name:UIKeyboardWillShowNotification
         object:nil];
[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillHide:)
           name:UIKeyboardWillHideNotification
         object:nil];
Run Code Online (Sandbox Code Playgroud)

实现类似于下面的方法,以便在键盘显示后调整tableView的大小以匹配可见区域.这里我分别跟踪键盘的状态,因此我可以选择何时将tableView设置回自己的全高,因为您在每次更改字段时都会收到这些通知.不要忘记实现keyboardWillHide:并选择适合的地方来修复tableView大小.

-(void) keyboardWillShow:(NSNotification *)note
{
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
    keyboardHeight = keyboardBounds.size.height;
    if (keyboardIsShowing == NO)
    {
        keyboardIsShowing = YES;
        CGRect frame = self.view.frame;
        frame.size.height -= keyboardHeight;

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationDuration:0.3f];
        self.view.frame = frame;
        [UIView commitAnimations];
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这里的滚动位,我们制定出了几个规模第一,然后我们看到我们在可见区域,并设置我们要滚动到RECT要高于或文本字段的基于偏下半视它在视图中的位置.在这种情况下,我们有UITextFields数组和跟踪他们的枚举,所以由行号的rowHeight乘以为我们提供了实际的这种外视图中的帧偏移.

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame = textField.frame;
    CGFloat rowHeight = self.tableView.rowHeight;
    if (textField == textFields[CELL_FIELD_ONE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_ONE;
    }
    else if (textField == textFields[CELL_FIELD_TWO])
    {
        frame.origin.y += rowHeight * CELL_FIELD_TWO;
    }
    else if (textField == textFields[CELL_FIELD_THREE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_THREE;
    }
    else if (textField == textFields[CELL_FIELD_FOUR])
    {
        frame.origin.y += rowHeight * CELL_FIELD_FOUR;
    }
    CGFloat viewHeight = self.tableView.frame.size.height;
    CGFloat halfHeight = viewHeight / 2;
    CGFloat midpoint = frame.origin.y + (textField.frame.size.height / 2);
    if (midpoint < halfHeight)
    {
        frame.origin.y = 0;
        frame.size.height = midpoint;
    }
    else
    {
        frame.origin.y = midpoint;
        frame.size.height = midpoint;
    }
    [self.tableView scrollRectToVisible:frame animated:YES];
}
Run Code Online (Sandbox Code Playgroud)

这看起来效果很好.

  • 从iOS 3.2开始,不推荐使用`UIKeyboardBoundsUserInfoKey`.请参阅下面的解决方案,该解决方案适用于所有当前版本≥3.0/@ iPhoneDev (2认同)

Ort*_*ntz 35

如果您可以使用UITableViewController,您将免费获得该功能.但是,有时候这不是一个选项,特别是如果您需要多个视图而不仅仅是UITableView.

这里提出的一些解决方案不适用于iOS≥4,有些不适用于iPad或横向模式,有些不适用于蓝牙键盘(我们不希望任何滚动),有些则不适用在多个文本字段之间切换时工作.因此,如果您选择任何解决方案,请务必测试这些情况.这是我们的解决方案使用 用于InAppSettingsKit:

- (void)_keyboardWillShow:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        // we don't use SDK constants here to be universally compatible with all SDKs ? 3.0
        NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
        if (!keyboardFrameValue) {
            keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
        }

        // Reduce the tableView height by the part of the keyboard that actually covers the tableView
        CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            windowRect = IASKCGRectSwap(windowRect);
        }
        CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        }
        CGRect frame = _tableView.frame;
        frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = frame;
        [UIView commitAnimations];

        UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
        NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

        // iOS 3 sends hide and show notifications right after each other
        // when switching between textFields, so cancel -scrollToOldPosition requests
        [NSObject cancelPreviousPerformRequestsWithTarget:self];

        [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)_keyboardWillHide:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = self.view.bounds;
        [UIView commitAnimations];

        [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
    }
}   
Run Code Online (Sandbox Code Playgroud)

这是InAppSettingsKit中该类完整代码.要测试它,请使用"完整列表"子窗格,您可以在其中测试上述方案.


Bar*_*zyk 24

Swift最简单的解决方案:

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar?.becomeFirstResponder()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
            tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    UIView.animateWithDuration(0.2, animations: { self.table_create_issue.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) })
    // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
    }
Run Code Online (Sandbox Code Playgroud)


Hus*_*tee 7

我希望你们已经有了解决所有这些问题的解决方案.但我发现我的解决方案如下.我期待你已经有了一个单元格UITextField.所以在准备时只需将行索引保留在文本字段的标记中.

cell.textField.tag = IndexPath.row;
Run Code Online (Sandbox Code Playgroud)

创建一个具有全局范围的activeTextField实例,UITextField如下所示:

@interface EditViewController (){

    UITextField *activeTextField;

}
Run Code Online (Sandbox Code Playgroud)

所以,现在你只需复制粘贴我的代码.而且别忘了添加UITextFieldDelegate

#pragma mark - TextField Delegation

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{

    activeTextField = textField;

    return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField{

    activeTextField = nil;

}
Run Code Online (Sandbox Code Playgroud)

注册键盘 notifications

#pragma mark - Keyboard Activity

- (void)registerForKeyboardNotifications

{

    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWasShown:)

                                             name:UIKeyboardDidShowNotification object:nil];



    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWillBeHidden:)

                                             name:UIKeyboardWillHideNotification object:nil];



}
Run Code Online (Sandbox Code Playgroud)

处理键盘Notifications:

UIKeyboardDidShowNotification发送时调用.

- (void)keyboardWasShown:(NSNotification*)aNotification

{

    NSDictionary* info = [aNotification userInfo];

    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

    NSIndexPath *currentRowIndex = [NSIndexPath indexPathForRow:activeTextField.tag inSection:0];

    [self.tableView scrollToRowAtIndexPath:currentRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

}
Run Code Online (Sandbox Code Playgroud)

UIKeyboardWillHideNotification发送时调用

- (void)keyboardWillBeHidden:(NSNotification*)aNotification

{

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

}
Run Code Online (Sandbox Code Playgroud)

现在剩下一件事,调用registerForKeyboardNotifications方法in ViewDidLoad方法如下:

- (void)viewDidLoad {

    [super viewDidLoad];

    // Registering keyboard notification

    [self registerForKeyboardNotifications];

    // Your codes here...

}
Run Code Online (Sandbox Code Playgroud)

你完成了,希望你的textFields意志不再被键盘隐藏.


Col*_*lin 6

结合并填充几个答案的空白(特别是Ortwin Gentz,用户98013)和另一篇文章,这将在纵向或横向模式的iPad上开箱即用:

@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
  if (self.isFirstResponder) {        
    return self;     
  }

  for (UIView *subView in self.subviews) {
    UIResponder *firstResponder = [subView findFirstResponder];
    if (firstResponder != nil) {
      return firstResponder;
    }
  }

  return nil;
}
@end

@implementation MyViewController

- (UIResponder *)currentFirstResponder {
  return [self.view findFirstResponder];
}

- (IBAction)editingEnded:sender {
  [sender resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
  [textField resignFirstResponder];
  return NO;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
  UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
  [_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillShow:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {
    NSDictionary* userInfo = [notification userInfo];

    // we don't use SDK constants here to be universally compatible with all SDKs ? 3.0
    NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
    if (!keyboardFrameValue) {
      keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
    }

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect frame = _tableView.frame;
    if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
      windowRect = CGRectMake(windowRect.origin.y, windowRect.origin.x, windowRect.size.height, windowRect.size.width);
      viewRectAbsolute = CGRectMake(viewRectAbsolute.origin.y, viewRectAbsolute.origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
    }
    frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = frame;
    [UIView commitAnimations];

    UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
    NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

    // iOS 3 sends hide and show notifications right after each other
    // when switching between textFields, so cancel -scrollToOldPosition requests
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    _topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
    [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillHide:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {

    NSDictionary* userInfo = [notification userInfo];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = self.view.bounds;
    [UIView commitAnimations];

    [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
  }
}   

@end
Run Code Online (Sandbox Code Playgroud)


Cor*_*oyd 5

如果你使用uitableview来放置文本字段(来自Jeff Lamarche),你可以使用委托方法滚动tableview,就像这样.

(注意:我的文本字段存储在一个数组中,其索引与tableview中的行相同)

- (void) textFieldDidBeginEditing:(UITextField *)textField
    {

        int index;
        for(UITextField *aField in textFields){

            if (textField == aField){
                index = [textFields indexOfObject:aField]-1;
            }
        }

         if(index >= 0) 
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];

        [super textFieldDidBeginEditing:textField];
    }
Run Code Online (Sandbox Code Playgroud)


Dus*_*oss 5

键盘通知有效,但Apple的示例代码假定滚动视图是窗口的根视图.通常情况并非如此.您必须补偿标签栏等,以获得正确的偏移量.

它听起来比听起来容易.这是我在UITableViewController中使用的代码.它有两个实例变量,hiddenRect和keyboardShown.

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification {
    if (keyboardShown)
        return;

    NSDictionary* info = [aNotification userInfo];

    // Get the frame of the keyboard.
    NSValue *centerValue = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
    NSValue *boundsValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    CGPoint keyboardCenter = [centerValue CGPointValue];
    CGRect keyboardBounds = [boundsValue CGRectValue];
    CGPoint keyboardOrigin = CGPointMake(keyboardCenter.x - keyboardBounds.size.width / 2.0,
                                         keyboardCenter.y - keyboardBounds.size.height / 2.0);
    CGRect keyboardScreenFrame = { keyboardOrigin, keyboardBounds.size };


    // Resize the scroll view.
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = scrollView.frame;
    CGRect keyboardFrame = [scrollView.superview convertRect:keyboardScreenFrame fromView:nil];
    hiddenRect = CGRectIntersection(viewFrame, keyboardFrame);

    CGRect remainder, slice;
    CGRectDivide(viewFrame, &slice, &remainder, CGRectGetHeight(hiddenRect), CGRectMaxYEdge);
    scrollView.frame = remainder;

    // Scroll the active text field into view.
    CGRect textFieldRect = [/* selected cell */ frame];
    [scrollView scrollRectToVisible:textFieldRect animated:YES];

    keyboardShown = YES;
}


// Called when the UIKeyboardDidHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
    // Reset the height of the scroll view to its original value
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = [scrollView frame];
    scrollView.frame = CGRectUnion(viewFrame, hiddenRect);

    keyboardShown = NO;
}
Run Code Online (Sandbox Code Playgroud)


小智 5

如果您使用Three20,则使用该autoresizesForKeyboard属性.只需在视图控制器的-initWithNibName:bundle方法中设置即可

self.autoresizesForKeyboard = YES
Run Code Online (Sandbox Code Playgroud)

这需要注意:

  1. 收听键盘通知并调整表格视图的框架
  2. 滚动到第一个响应者

做完了.


小智 5

我的方法:

我首先将UITextField子类化并添加一个indexPath属性.在cellFor ...方法中,我移交了indexPath属性.

然后我添加以下代码:

UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:textField.indexPath];

CGPoint cellPoint = [cell convertPoint:textField.center toView:self.tableView];
[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, cellPoint.y-50);}];
Run Code Online (Sandbox Code Playgroud)

到textFieldShould/WillBegin ...等.

当键盘消失时,您必须将其反转:

[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, 0);}];
Run Code Online (Sandbox Code Playgroud)


Vas*_*ily 5

Swift 4.2 完整解决方案

我创建了带有一组协议的 GIST,这些协议通过在显示、隐藏或更改键盘时添加额外空间来简化工作。

特点

  • 正确处理键盘框架更改(例如键盘高度更改,如 emojii?普通键盘)。
  • TabBar 和 ToolBar 支持 UITableView 示例(在其他示例中,您会收到不正确的插图)。
  • Dynamic animation duration (not hard-coded).
  • Protocol-oriented approach that could be easily modified for you purposes.

Usage

Basic usage example in view controller that contains some scroll view (table view is supported also of course).

class SomeViewController: UIViewController {
  @IBOutlet weak var scrollView: UIScrollView!

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    addKeyboardFrameChangesObserver()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeKeyboardFrameChangesObserver()
  }
}

extension SomeViewController: ModifableInsetsOnKeyboardFrameChanges {
  var scrollViewToModify: UIScrollView { return scrollView }
}
Run Code Online (Sandbox Code Playgroud)

Core: frame changes observer

Protocol KeyboardChangeFrameObserver will fire event each time keyboard frame was changed (including showing, hiding, frame changing).

  1. Call addKeyboardFrameChangesObserver() at viewWillAppear() or similar method.
  2. Call removeKeyboardFrameChangesObserver() at viewWillDisappear() or similar method.

Implementation: scrolling view

ModifableInsetsOnKeyboardFrameChanges protocol adds UIScrollView support to core protocol. It changes scroll view's insets when keyboard frame is changed.

Your class needs to set scroll view, one's insets will be increased / decreased on keyboard frame changes.

var scrollViewToModify: UIScrollView { get }
Run Code Online (Sandbox Code Playgroud)


Ken*_*ner 3

由于表格中有文本字段,最好的方法实际上是调整表格大小 - 您需要将 tableView.frame 的高度设置为较小键盘的大小(我认为大约 165 像素),然后在以下情况下再次展开它:键盘被解除。

如果您不希望用户滚动,您也可以选择禁用 tableView 的用户交互。