Изменение размера представления при появлении клавиатуры (iOS)

Я понимаю, что существует много подобных решений, таких как TPKeyboardAvoiding, знаменитое решение Apple и различные предложения, связанные с использованием 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: но ничто из того, что я пытаюсь, никуда меня не доставит.

Я действительно надеюсь, что кто-то, кто меньше смущает все эти прямоугольники и как они меняются, когда изменения ориентации могут определить, что я делаю неправильно, и что мне нужно сделать, чтобы это исправить. Для справки, я создал проект, демонстрирующий простейший случай, который воспроизводит проблему, которую я имею.

Ответ 1

Я не советую вам изменять размер корневого представления для вашего контроллера представлений, вы можете создать contentView и добавить в просмотр контроллера вида. Вы можете изменить размер этого contentView, как показано ниже (я не использую autolayouting):

- (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];
}

Ответ 2

Виталий Б ответ быстро. Я получил представление под названием 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)
}

Ответ 4

Я сделал это, надеюсь, этот код будет полезен для u.

- (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;
}

Ответ 5

Попробуйте эти методы. Отредактируйте его в соответствии с вашими требованиями.

#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 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];
}