【问题标题】:How do I resize views when keyboard pops up using Auto Layout使用自动布局弹出键盘时如何调整视图大小
【发布时间】:2014-07-22 05:40:24
【问题描述】:

我的UIViewController 上有一个视图(在这种情况下是UITableView,但这并不重要),我希望在键盘弹出时调整高度。

在自动布局中执行此操作的最佳方法是什么?目前在视图上我有这些限制:

  • 要查看的顶部空间:0
  • superview 的尾随空格:0
  • 领先空间到superview:0
  • superview 的底部空间:0
  • 高度等于 = 424

我认为最快的方法是在调用keyboardDidAppear 通知时删除高度和底部空间限制,并在代码中调整实际视图的大小,但是还有其他方法吗?

编辑:我删除了高度限制,我的错。

【问题讨论】:

  • 在这种情况下,最好更新contentInset 属性而不是更改实际布局。

标签: ios uitableview interface-builder autolayout


【解决方案1】:

首先,您不应该添加上下约束和高度约束。如果屏幕尺寸发生变化,应用程序将崩溃(除非其中一个约束的优先级较低,在这种情况下它将被移除)。

其次,在您的keyboardDidAppear通知方法中,您只需将底部空间更改为superview的常量值并调用[myView setNeedsDisplay]

编辑:您在 becomeFirstResponder 之后不执行 setNeedsDisplay。您将self 添加为keyboardWillShow / keyboardWillHide 通知的观察者,然后在该方法中更新约束并调用setNeedsDisplay

看看this apple postListing 5-1 Handling the keyboard notificationsListing 5-2 Additional methods for tracking the active text field提供代码。

【讨论】:

  • 嘿,感谢 Zsolt 勋爵,但是在我调用之后,视图似乎仍然没有调整大小。我也删除了高度限制。在我打电话给becomeFirstResponder 调出键盘之后,我马上打电话给setNeedsDisplay
【解决方案2】:

保持高度限制并连接插座:

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *CS_TableView_Height;

查看this tutorial 的示例 3。

通过使用NSNotificationCenter 捕获键盘事件来更新视图的高度:

- (void)viewWillAppear:(BOOL)animated
{
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

您可能还想看看this question 接受的答案以获得一些灵感。

所以最后,你应该得到这样的结果:

- (void)keyboardWillShow
{

    self.CS_TableView_Height.constant = 500;//For example

    [self.tableView setNeedsUpdateConstraints];
}

- (void)keyboardWillHide
{

    self.CS_TableView_Height.constant = 568;// iPhone5 height

    [self.tableView setNeedsUpdateConstraints];
}

【讨论】:

  • 1.基于块的通知更加方便和更好的实践。 2. 更新contentInset 属性也是一种更好的做法。
  • @holex:您能否提供一些解决方案的代码作为答案? :)
  • 我很快就会尝试这个,但我认为像这样指定常数作为高度不是一个好主意。日文或中文等其他键盘的高度可能与英文键盘不同。
  • 所以你只需要获取键盘的高度并动态减去它
  • @NhonNguyen,是的,没问题,但是我更喜欢仅在我不了解整个环境的情况下提供想法(例如在这种情况下)。
【解决方案3】:

我会给你一个通用的想法,它可能需要根据你的实际项目重新调整。

斯威夫特 4.2

let notificationTokenKeyboardWillAppear = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { (note) in
    guard let keyboardFrame = (note.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
    UIView.animate(withDuration: CATransaction.animationDuration(), animations: {
        self.scrollView?.contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardFrame.size.height, right: 0.0)
    }, completion: nil)
}

let notificationTokenKeyboardWillHide = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: nil) { (_) in
    UIView.animate(withDuration: CATransaction.animationDuration(), animations: {
        self.scrollView?.contentInset = .zero
    }, completion: nil)
}

NOTE-1: scrollView 在这里代表UIScrollView 的任何子集,例如UITableViewUICollectionView 等...

注意 2: 当您即将释放视图时,您需要通过调用 removeObserver(_:) 方法手动删除标记,并且不需要基于闭包的观察者不再


ObjC

我认为UITableView *_tableView 之前在某处已正确设置。

- (void)viewDidLoad {

    // ...

    [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
        id _obj = [note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
        CGRect _keyboardFrame = CGRectNull;
        if ([_obj respondsToSelector:@selector(getValue:)]) [_obj getValue:&_keyboardFrame];
        [UIView animateWithDuration:0.25f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{
            [_tableView setContentInset:UIEdgeInsetsMake(0.f, 0.f, _keyboardFrame.size.height, 0.f)];
        } completion:nil];
    }];
    
    [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillHideNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
        [UIView animateWithDuration:0.25f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{
            [_tableView setContentInset:UIEdgeInsetsZero];
        } completion:nil];
     }];


     // ...

}

注意:如果您的 UITableView 不在屏幕底部,则 contentInset 值应该在这一行细化: [_tableView setContentInset:UIEdgeInsetsMake(0.f, 0.f, _keyboardFrame.size.height, 0.f)];

【讨论】:

  • 非常感谢您的回答,我会试试这个。调整具有约束的视图的大小通常不是一个好主意吗?当我们有这样的约束时,使用 contentInset 会更好吗?
  • @EnricoSusatyo,我认为仅仅因为键盘外观而调整视图大小太不方便了。另一方面,contentInset 属性及其行为为此目的而设计得很好。
  • 感谢您的回答,它几乎可以完美运行。唯一让我不太满意的是,一半的滚动条仍然隐藏在键盘后面,但表格视图内容现在在键盘上方可见。但是我认为这仍然是迄今为止最好的解决方案。
  • 感谢您的出色解决方案!为这个问题加了星标。
  • 注意: 还要设置 scrollIndicatorInsets 以便滚动条正确移动。
猜你喜欢
  • 2012-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-20
  • 1970-01-01
相关资源
最近更新 更多