UIKeyboardBoundsUserInfoKey устарела, что использовать вместо этого? - PullRequest
49 голосов
/ 11 мая 2010

Я работаю над приложением для iPad, используя 3.2 SDK. Я имею дело с получением размера клавиатуры, чтобы мои текстовые поля не скрывались за ней.

Я получаю предупреждение в Xcode -> UIKeyboardBoundsUserInfoKey устарела, что я должен использовать вместо этого, чтобы не получать это предупреждение?

Ответы [ 9 ]

87 голосов
/ 29 мая 2010

Я играл с ранее предложенным решением, но у меня все еще были проблемы. Вот что я придумал вместо этого:

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

    - (void)keyboardWillHide:(NSNotification *)aNotification {
        [self moveTextViewForKeyboard:aNotification up:NO]; 
    }

- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];

// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;

CGRect keyboardEndFrame;

[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];


[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];


// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];

CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];

newFrame.origin.y -= keyboardFrame.size.height * (up? 1 : -1);
textView.frame = newFrame;

[UIView commitAnimations];
}
55 голосов
/ 11 мая 2010

Из документации для UIKeyboardBoundsUserInfoKey:

Ключ для объекта NSValue, содержащего CGRect, который идентифицирует прямоугольник границ клавиатуры в координатах окна. Этого значения достаточно для получения размера клавиатуры. Если вы хотите получить происхождение клавиатуры на экране (до или после анимации), используйте значения, полученные из пользовательского словаря информации через константы UIKeyboardCenterBeginUserInfoKey или UIKeyboardCenterEndUserInfoKey. Вместо этого используйте ключ UIKeyboardFrameBeginUserInfoKey или UIKeyboardFrameEndUserInfoKey.

Apple рекомендует реализовать удобную процедуру, такую ​​как эта (которая может быть реализована как дополнение категории к UIScreen):

+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view {
    UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window];
    return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil];
}

для восстановления настроенных в окне свойств размера рамки клавиатуры.

Я выбрал другой подход, который включает проверку ориентации устройства:

CGRect _keyboardEndFrame;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&_keyboardEndFrame];
CGFloat _keyboardHeight = ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) ? _keyboardEndFrame.size.height : _keyboardEndFrame.size.width;
9 голосов
/ 02 декабря 2010

Вы просто используете этот код:

//NSVale *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
//instead of Upper line we can use either next line or nextest line.
//NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
3 голосов
/ 18 октября 2012

Следующий код исправляет проблему в ответе Джея , в которой предполагается, что UIKeyboardWillShowNotification не сработает снова, когда клавиатура уже присутствует.

При наборе текста на японской / китайской клавиатуре iOS запускает дополнительный UIKeyboardWillShowNotification с новой рамкой клавиатуры, даже если клавиатура уже присутствует, что приводит к уменьшению высоты self.textView во второй раз в исходном коде .

Это уменьшает self.textView почти до нуля. Тогда становится невозможно решить эту проблему, так как мы ожидаем только один UIKeyboardWillHideNotification в следующий раз, когда клавиатура будет закрыта.

Вместо вычитания / добавления высоты к self.textView в зависимости от того, отображается или скрывается клавиатура, как в исходном коде, следующий код просто вычисляет максимально возможную высоту для self.textView после вычитания высоты клавиатуры на экране. .

Предполагается, что self.textView предполагает заполнение всего представления контроллера представления, и нет никакого другого подпредставления, которое должно быть видимым.

- (void)resizeTextViewWithKeyboardNotification:(NSNotification*)notif {

    NSDictionary* userInfo = [notif userInfo];
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrameInWindowsCoordinates;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindowsCoordinates];

    [self resizeTextViewToAccommodateKeyboardFrame:keyboardFrameInWindowsCoordinates
                             withAnimationDuration:animationDuration
                                    animationCurve:animationCurve];

}

- (void)resizeTextViewToAccommodateKeyboardFrame:(CGRect)keyboardFrameInWindowsCoordinates
                           withAnimationDuration:(NSTimeInterval)duration
                                  animationCurve:(UIViewAnimationCurve)curve
{

    CGRect fullFrame = self.view.frame;

    CGRect keyboardFrameInViewCoordinates =
    [self.view convertRect:keyboardFrameInWindowsCoordinates fromView:nil];

    // Frame of the keyboard that intersects with the view. When keyboard is
    // dismissed, the keyboard frame still has width/height, although the origin
    // keeps the keyboard out of the screen.
    CGRect keyboardFrameVisibleOnScreen =
    CGRectIntersection(fullFrame, keyboardFrameInViewCoordinates);

    // Max frame availble for text view. Assign it to the full frame first
    CGRect newTextViewFrame = fullFrame;

    // Deduct the the height of any keyboard that's visible on screen from
    // the height of the text view
    newTextViewFrame.size.height -= keyboardFrameVisibleOnScreen.size.height;

    if (duration)
    {
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:duration];
        [UIView setAnimationCurve:curve];
    }

    // Adjust the size of the text view to the new one
    self.textView.frame = newTextViewFrame;

    if (duration)
    {
        [UIView commitAnimations];
    }

}

Также не забудьте зарегистрировать уведомления клавиатуры в viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSNotificationCenter* notifCenter = [NSNotificationCenter defaultCenter];

    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillShowNotification object:nil];
    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillHideNotification object:nil];
}

О разбиении кода изменения размера на две части

Причина, по которой код изменения размера textView разделен на две части (resizeTextViewWithKeyboardNotification: и resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:), заключается в том, чтобы устранить другую проблему, когда клавиатура сохраняется после перехода от одного контроллера представления к другому (см. Как мне обнаружить клавиатуру iOS, когда она остается между контроллерами? ).

Поскольку клавиатура уже присутствует до нажатия контроллера представления, iOS не генерирует никаких дополнительных уведомлений клавиатуры, и, следовательно, нет способа изменить размер textView на основе этих уведомлений клавиатуры.

Приведенный выше код (а также исходный код), который изменяет размер self.textView, будет работать, только когда клавиатура отображается после , когда представление было загружено.

Мое решение заключается в создании синглтона, в котором хранятся последние координаты клавиатуры, и на - viewDidAppear: viewController вызовите:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Resize the view if there's any keyboard presence before this
    // Only call in viewDidAppear as we are unable to convertRect properly
    // before view is shown
    [self resizeViewToAccommodateKeyboardFrame:[[UASKeyboard sharedKeyboard] keyboardFrame]
                         withAnimationDuration:0
                                animationCurve:0];
}

UASKeyboard мой синглтон здесь. В идеале мы должны вызывать это в - viewWillAppear:, однако, по моему опыту (по крайней мере, в iOS 6), метод convertRect:fromView:, который нам нужно использовать в resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:, неправильно преобразовывает кадр клавиатуры в координаты представления перед просмотром полностью виден.

2 голосов
/ 05 октября 2012

Просто используйте клавишу UIKeyboardFrameBeginUserInfoKey или UIKeyboardFrameEndUserInfoKey вместо UIKeyboardBoundsUserInfoKey

1 голос
/ 07 марта 2011
- (CGSize)keyboardSize:(NSNotification *)aNotification {
    NSDictionary *info = [aNotification userInfo];
    NSValue *beginValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    CGSize keyboardSize;
    if ([UIKeyboardDidShowNotification isEqualToString:[aNotification name]]) {
        _screenOrientation = orientation;
        if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize = [beginValue CGRectValue].size;
        } else {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        }
    } else if ([UIKeyboardDidHideNotification isEqualToString:[aNotification name]]) {
        // We didn't rotate
        if (_screenOrientation == orientation) {
            if (UIDeviceOrientationIsPortrait(orientation)) {
                keyboardSize = [beginValue CGRectValue].size;
            } else {
                keyboardSize.height = [beginValue CGRectValue].size.width;
                keyboardSize.width = [beginValue CGRectValue].size.height;
            }
        // We rotated
        } else if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        } else {
            keyboardSize = [beginValue CGRectValue].size;
        }
    }


    return keyboardSize;
}
1 голос
/ 22 июня 2010

@ Джейсон, если ты в порядке, за исключением одного пункта.

В настоящий момент вы ничего не анимируете, и представление просто «выскочит» на свой новый размер. Высота.

Вы должны указать состояние для анимации. Анимация - это что-то вроде (из состояния) -> (для состояния).

К счастью, есть очень удобный способ указать текущее состояние представления как (из состояния).

[UIView setAnimationBeginsFromCurrentState:YES];

Если вы добавите эту строку сразу после beginAnimations: context: ваш код работает отлично.

0 голосов
/ 15 февраля 2019

Это сработало так

Это ограничение нижней части кнопки сохранения

@IBOutlet weak var saveBtnBottom: NSLayoutConstraint!
@IBOutlet weak var nameText: UITextField!

Inside viewDidLoad

NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
nameText.delegate = self

Это те функции, которые нам нужны

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    nameText.resignFirstResponder()
    return true
}


@objc func keyBoardWillShow(notification: Notification){
    if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
        let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
        let keyBoardRect = frame?.cgRectValue
        if let keyBoardHeight = keyBoardRect?.height {
            self.saveBtnBottom.constant = keyBoardHeight 

            UIView.animate(withDuration: 0.5, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }
}

@objc func keyBoardWillHide(notification: Notification){
    self.saveBtnBottom.constant = 30.0
    UIView.animate(withDuration: 0.5, animations: {
        self.view.layoutIfNeeded()
    })
}
0 голосов
/ 18 января 2012
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...