Неправильная высота расширения клавиатуры после поворота

У меня есть специальная клавиатура iOS, которая меняет высоту при вращении.

Мой код работает нормально в 95% случаев... Но в некоторых случаях (см. ниже) высота не меняется при повороте в альбомную - сохраняется портретная высота.

Проблема может быть воспроизведена с помощью этого (почти) минимального кода — создайте новую цель расширения клавиатуры и скопируйте этот код в KeyboardViewController:

class KeyboardViewController: UIInputViewController {
    private var orangeView = UIView()
    private var heightConstraint: NSLayoutConstraint!
    @IBOutlet var nextKeyboardButton: UIButton!

    override func updateViewConstraints() {
        super.updateViewConstraints()
        let screenSize = UIScreen.mainScreen().bounds.size
        let screenH = screenSize.height
        let screenW = screenSize.width
        let isLandscape = !(self.view.frame.size.width == screenW * ((screenW < screenH) ? 1 : 0) + screenH * ((screenW > screenH) ? 1 : 0))
        let desiredHeight: CGFloat = isLandscape ? 193 : 252
        if heightConstraint.constant != desiredHeight {
            heightConstraint!.constant = desiredHeight
            orangeView.frame = CGRect(x: 0, y: 0, width: screenW, height: isLandscape ? 193 : 252)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        nextKeyboardButton = UIButton(type: .System)
        nextKeyboardButton.setTitle("Next Keyboard", forState: .Normal)
        nextKeyboardButton.sizeToFit()
        nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false
        nextKeyboardButton.addTarget(self, action: "advanceToNextInputMode", forControlEvents: .TouchUpInside)
        heightConstraint = NSLayoutConstraint(item:self.inputView!, attribute:.Height, relatedBy:.Equal, toItem:nil, attribute:.NotAnAttribute, multiplier: 0.0, constant: 0) //preparing heightConstraint
        heightConstraint?.priority = 999
        orangeView.backgroundColor = UIColor.orangeColor()
        view.addSubview(orangeView)
        view.addSubview(self.nextKeyboardButton)
        let nextKeyboardButtonLeftSideConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 0.0)
        let nextKeyboardButtonBottomConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
        view.addConstraints([nextKeyboardButtonLeftSideConstraint, nextKeyboardButtonBottomConstraint])
    }

    override func viewWillAppear(animated: Bool) {
        if self.view.constraints.filter({c in c == self.heightConstraint}).isEmpty {
            self.view.addConstraint(heightConstraint)
        }
        view.setNeedsUpdateConstraints() //ensures that updateViewConstraints always gets called at least once
        super.viewWillAppear(animated)
    }
}

Для получения дополнительной информации о том, как это работает, см. это и этот ответ.

Когда вы запускаете клавиатуру, она, вероятно, будет работать нормально — она немного выше, и после поворота оранжевый вид покрывает всю клавиатуру:

введите здесь описание изображения

Однако вы также можете получить это (высота портрета сохраняется после поворота):

введите здесь описание изображения

Действия для воспроизведения проблемы (с кодом выше):

  1. Откройте клавиатуру в приложении «Сообщения», поверните альбомную ориентацию и обратно
  2. Если вы не увидели проблему, выключите приложение «Сообщения» (нажмите кнопку «Домой» 2 раза -> проведите пальцем вверх по сообщениям).
  3. Открывайте сообщения снова, поворачивайте альбомную ориентацию и обратно
  4. Возможно, вам придется повторить шаги 1–3 несколько раз, чтобы увидеть проблему (обычно не более 2–4 раз).

Что я знаю:

  • Если вы видите проблему, вы будете видеть ее до тех пор, пока клавиатура не будет скрыта и снова не отобразится.
  • Если вы видите, что проблема скрывает и повторно отображает клавиатуру в том же приложении - проблема всегда исчезает.
  • Проблема может появиться снова только после закрытия и перезапуска приложения хостинга.
  • Отладчик показывает, что heightConstraint!.constant равно 193, но и view.frame.height, и view.window?.frame.height по-прежнему 253 (изменение кадра напрямую не исправляет это)

Что я пробовал:

  • Вместо того, чтобы просто установить ограничение heightConstraint!.constant = desiredHeight, сначала удалите его из view, установите новое значение, а затем снова добавьте его.
  • Я проверил, что heightConstraint!.constant всегда меняется, когда это должно быть

Как исправить или обойти эту проблему? Должно быть решение, потому что SwiftKey не имеет этой проблемы.


person Rasto    schedule 22.03.2016    source источник


Ответы (1)


Я столкнулся с аналогичной проблемой с расширением клавиатуры: на моделях iPhone 6+ оно всегда не могло правильно установить свою высоту при повороте в первый раз, когда клавиатура вызывалась в приложение, а иногда и на iPhone 6 и других моделях iPhone.

В конце концов я нашел решение, хотя у него есть свои недостатки.

Во-первых, в документации указано, что

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

Вы устанавливаете ограничение по высоте в -[UIViewController viewWillAppear:], что, согласно строгой интерпретации документации, слишком рано. Если вы установите его в -[UIViewController viewDidAppear:], проблема, с которой вы сейчас сталкиваетесь, должна быть решена.

Однако затем вы можете обнаружить, что ваша регулировка высоты визуально раздражает, так как это происходит после появления клавиатуры.

Я понятия не имею, как SwiftKey удается установить их высоту (по-видимому) до появления клавиатуры и избежать этой проблемы.

person Ben Pious    schedule 22.03.2016
comment
Спасибо! Похоже, добавление ограничения в viewDidAppear решает проблему. Что касается возникшей проблемы с визуальной регулировкой высоты: на основе моего тестирования на iOS 9 первое появление в приложении всегда в порядке, любое последующее появление вызывает раздражение, независимо от того, добавлено ли ограничение в viewWillAppear или viewDidAppear. На iOS 8 разница есть, но не такая большая... У вас другой опыт? - person Rasto; 23.03.2016