it-swarm.com.ru

UIKeyboardBoundsUserInfoKey устарела, что использовать вместо этого?

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

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

49
Mikeware

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

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

Из документации для 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;
55
Alex Reynolds

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

//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];
9
iOS_User

Следующий код исправляет проблему в ответ Джея , которая предполагает, что 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:), состоит в том, чтобы исправить другую проблему, когда клавиатура сохраняется через Push от одного контроллера представления к другому (см. Как обнаружить клавиатуру 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:, не преобразует должным образом кадр клавиатуры в координаты вида, прежде чем вид станет полностью видимым.

3
junjie

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

2
Anand Mishra

@ Джейсон, если хорошо, закодируй, кроме одного пункта.

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

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

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

[UIView setAnimationBeginsFromCurrentState:YES];

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

1
Thomas
- (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
Cameron Lowell Palmer
0
karim

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

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

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

Внутри 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
Mohammed Abunada