当键盘弹出时调整视图大小 (iOS)

13
我知道有很多类似的解决方案,比如TPKeyboardAvoiding苹果著名的解决方案以及各种建议涉及使用UIScrollView。在我的情况下,我需要调整一个视图来适应键盘而不是滚动或移动它。这个解决方案最接近我想要实现的效果,因此它是我的基础。然而,我在横屏模式下遇到了问题。当键盘出现时,我的方法会调整视图大小,代码如下:
- (void)keyboardWillShow:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];

    CGRect keyboardFrame = [[self textField].superview convertRect:[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil];
    CGRect statusBarFrame = [[self textField].superview convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil];

    CGRect bounds = [self textField].superview.bounds;    
    CGRect newFrame = CGRectMake(0.0, 0.0, bounds.size.width, keyboardFrame.origin.y + statusBarFrame.size.height);
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        [self textField].superview.frame = newFrame;
    } completion:nil];
}

这在竖屏模式下完美运行。

enter image description here

在横向模式下,视图的大小会根据设备旋转的方向从左到右或从右到左重新调整大小,而不是从底部向上。

enter image description here

很明显,我在使用坐标时出现了问题,某些参考框架在横向模式下并不是我所认为的那样,但我很难弄清楚如何解决它。我尝试使用-convertRect:将所有东西转换成各种形式,但是我试过的任何方法都没有帮助我。

我真的希望有人能够比我更清楚地理解所有这些矩形以及它们在方向改变时如何变化,找出我做错了什么,以及我需要做什么才能解决这个问题。供参考,我已经创建了一个项目,展示了我遇到的问题的最简单情况。


当键盘可见时,您想要旋转iPan吗? - Vitaly Berg
理想情况下是这样的,因为我相信有些用户会这样做。但是我认为,如果我能让这个解决方案运行起来(我正在添加一个当键盘隐藏时调整视图大小的方法),那么它将自动工作。我相信当设备旋转并显示键盘时,iOS会连续发送keyboardWillHide和keyboardWillShow通知。 - bkocik
谢谢提供动画代码,非常实用。 - phatmann
这里对 curve 的使用实际上是不正确的。请参考此线程:https://dev59.com/CGMk5IYBdhLWcg3wyw_H#18975862 - phatmann
5个回答

28

我不建议您调整视图控制器的根视图大小,您可以创建一个内容视图并将其添加到视图控制器的视图中。您可以按如下方式更改此内容视图的大小(我不使用自动布局):

- (void)keyboardWillShow:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        self.contentView.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
    } completion:nil];
}

- (void)keyboardWillHide:(NSNotification *)note {
    NSDictionary *userInfo = note.userInfo;
    NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
        self.contentView.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
    } completion:nil];
}

非常感谢!调整根视图大小是我唯一的问题吗?(除了在dealloc上没有将自己作为观察者移除以及没有代码在隐藏键盘时运行之外;我在实际应用程序中已经解决了这些问题。) - bkocik
现在这个应用程序非常简单,因此很难谈论任何更多的问题:)。将来可能出现的问题,您总是可以在这里解决。 - Vitaly Berg
1
两个通知处理程序中的代码是相同的,因此可以使用一个方法而不是两个。 - Richard Groves

8

Vitaliy B在Swift中的回答。我有一个叫做templateHeaderContentView的视图,我创建了一个函数并在那里配置了视图的高度。您可以使用自己的视图,并相应地更改高度。

func keyboardWillShow(notification: NSNotification) {
    keyboardShowOrHide(notification)
}

func keyboardWillHide(notification: NSNotification) {
    keyboardShowOrHide(notification)
}

private func keyboardShowOrHide(notification: NSNotification) {
    guard let userInfo = notification.userInfo else {return}
    guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey]else { return }
    guard let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] else { return }
    guard let keyboardFrameEnd = userInfo[UIKeyboardFrameEndUserInfoKey] else { return }

    let curveOption = UIViewAnimationOptions(rawValue: UInt(curve.integerValue << 16))
    let keyboardFrameEndRectFromView = view.convertRect(keyboardFrameEnd.CGRectValue, fromView: nil)
    UIView.animateWithDuration(duration.doubleValue ?? 1.0,
        delay: 0,
        options: [curveOption, .BeginFromCurrentState],
        animations: { () -> Void in
            self.templateHeaderContentView.configureView(keyboardFrameEndRectFromView.origin.y)
        }, completion: nil)
}

我使用了Vitaily的答案,但考虑到后人,建议包括configureView函数 ;) - gcasar

2

你试过那个解决方案吗?它不起作用。我在我的原始问题中提到了这一点。 - bkocik

1
我已经完成了,希望这段代码对你有所帮助。
- (void)viewWillAppear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];

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

- (void)keyboardWillShow:(NSNotification*)notification
{
    [self moveControls:notification up:YES];
}

- (void)keyboardWillBeHidden:(NSNotification*)notification
{
    [self moveControls:notification up:NO];
}

- (void)moveControls:(NSNotification*)notification up:(BOOL)up
{
    NSDictionary* userInfo = [notification userInfo];
    CGRect newFrame = [self getNewControlsFrame:userInfo up:up];

    [self animateControls:userInfo withFrame:newFrame];
}

- (CGRect)getNewControlsFrame:(NSDictionary*)userInfo up:(BOOL)up
{
    CGRect kbFrame = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    kbFrame = [self.view convertRect:kbFrame fromView:nil];

    CGRect newFrame = self.view.frame;
    newFrame.origin.y += kbFrame.size.height * (up ? -1 : 1);

    return newFrame;
}

- (void)animateControls:(NSDictionary*)userInfo withFrame:(CGRect)newFrame
{
    NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    UIViewAnimationCurve animationCurve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];

    [UIView animateWithDuration:duration
                          delay:0
                        options:animationOptionsWithCurve(animationCurve)
                     animations:^{
                         self.view.frame = newFrame;
                     }
                     completion:^(BOOL finished){}];
}

static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCurve curve)
{
    return (UIViewAnimationOptions)curve << 16;
}

非常努力,但是这个答案已经在两年前回答了。为了更好地利用你的技能,你可能想浏览一下标签中最近的问题列表。http://stackoverflow.com/questions/tagged/iphone?sort=newest&pageSize=30 - Nick Volynkin

-1

尝试这些方法。根据您的要求进行编辑。

#define kOFFSET_FOR_KEYBOARD 280.0

- (void)keyboardWillHide:(NSNotification *)notif {
    [self setViewMoveUp:NO];
}


- (void)keyboardWillShow:(NSNotification *)notif{
    [self setViewMoveUp:YES];
}


- (void)textFieldDidBeginEditing:(UITextField *)textField {
    stayup = YES;
    [self setViewMoveUp:YES];
}


- (void)textFieldDidEndEditing:(UITextField *)textField {
    stayup = NO;
    [self setViewMoveUp:NO];
}

//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMoveUp:(BOOL)moveUp
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3]; // if you want to slide up the view
    [UIView setAnimationBeginsFromCurrentState:YES];

    CGRect rect = self.view.frame;
    if (moveUp)
    {
        // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
        // 2. increase the size of the view so that the area behind the keyboard is covered up.

        if (rect.origin.y == 0 ) {
            rect.origin.y -= kOFFSET_FOR_KEYBOARD;
            //rect.size.height += kOFFSET_FOR_KEYBOARD;
        }

    }
    else
    {
        if (stayup == NO) {
            rect.origin.y += kOFFSET_FOR_KEYBOARD;
            //rect.size.height -= kOFFSET_FOR_KEYBOARD;
        }
    }
    self.view.frame = rect; 
    [UIView commitAnimations];
}

谢谢,但是这会移动视图 - 我需要调整大小 - 并且用硬编码的值;我更喜欢在运行时查找键盘的大小以保证未来兼容性。 - bkocik

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