iOS自动布局与滚动视图和键盘

12

我在我的故事板中有一个视图来显示用户登录表单,因此它看起来像这样:主视图->滚动视图->内容视图->两个文本字段和位于视图顶部的登录按钮以及位于底部的一个注册按钮。我使用自动布局,底部按钮有底部空间约束。当我点击文本字段并出现键盘时,我希望滚动视图更改大小以适合可见矩形区域,但内容大小应保持不变以便向下滚动到注册按钮,但是当滚动视图大小变化时,按钮会向上移动。我该如何实现我的想法?

当键盘出现时,我使用以下代码:

- (void)keyboardWillShow:(NSNotification *)aNotification
{
    NSDictionary *info = [aNotification userInfo];
    NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    CGRect keyboardFrame = [kbFrame CGRectValue];

    CGSize s = self.scrollView.contentSize;
    CGFloat height = keyboardFrame.size.height;
    self.scrollViewBottomLayoutConstraint.constant = height;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
        [self.scrollView setContentSize:s];
    }];
}
2个回答

31

尝试不要改变内容大小,而是调整滚动视图的contentInset属性。这样您就不必处理约束。

- (void)keyboardUp:(NSNotification *)notification
{
    NSDictionary *info = [notification userInfo];
    CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardRect = [self.view convertRect:keyboardRect fromView:nil];

    UIEdgeInsets contentInset = self.scrollView.contentInset;
    contentInset.bottom = keyboardRect.size.height;
    self.scrollView.contentInset = contentInset;
}

1
简单明了,但一个问题是滚动视图的滚动条不会根据滚动/表格/集合视图的可见部分进行调整大小。 - Nick Hingston
谢谢你,你节省了我的时间。 - riddhi

3
我发现最好的方法是像这样覆盖NSLayoutConstraint:
@implementation NHKeyboardLayoutConstraint

- (void) dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void) awakeFromNib {
    [super awakeFromNib];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillChangeFrame:)
                                                 name:UIKeyboardWillChangeFrameNotification
                                               object:nil];
}

- (void)keyboardWillChangeFrame:(NSNotification *)notification {

    CGRect endKBRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

    CGFloat animationDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
    CGRect frame = [UIApplication sharedApplication].keyWindow.bounds;

    self.constant = frame.size.height - endKBRect.origin.y;


    [UIView animateWithDuration:animationDuration animations:^{
        [[UIApplication sharedApplication].keyWindow layoutIfNeeded];
    }];
}


@end

然后在你的xib文件中,将有问题的约束的类类型更改为此类。


谢谢!我花了几天时间尝试使用Bilobatum描述的通常解决方案,以前我曾经成功地使用过。现在我有一个相当复杂的布局,必须被限制在底部,然后旧的“技巧”就不起作用了。 现在我只是用这个类替换了这个约束,它就起作用了!我做了一个小改动:float offset = 0; if (endKBRect.origin.y < frame.size.height) offset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom; self.constant = frame.size.height - endKBRect.origin.y - offset;支持没有Home键的手机。 - Janne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接