Как устранить ошибку API: возвращена ширина 0, предполагая UIViewNoIntrinsicMetric при изменении размера inputAccessoryView?

Я вставил образец кода отсюда: https://stackoverflow.com/a/46510833/784637 в новый единый вид. Приложение для закрепления inputAccessoryView внизу экрана:


class ViewController: UIViewController {

    override var canBecomeFirstResponder: Bool { return true }

    var _inputAccessoryView: UIView!

    override var inputAccessoryView: UIView? {

        if _inputAccessoryView == nil {

            _inputAccessoryView = CustomView()
            _inputAccessoryView.backgroundColor = UIColor.groupTableViewBackground

            let textField = UITextField()
            textField.borderStyle = .roundedRect

            _inputAccessoryView.addSubview(textField)

            _inputAccessoryView.autoresizingMask = .flexibleHeight

            textField.translatesAutoresizingMaskIntoConstraints = false

            textField.leadingAnchor.constraint(
                equalTo: _inputAccessoryView.leadingAnchor,
                constant: 8
            ).isActive = true

            textField.trailingAnchor.constraint(
                equalTo: _inputAccessoryView.trailingAnchor,
                constant: -8
            ).isActive = true

            textField.topAnchor.constraint(
                equalTo: _inputAccessoryView.topAnchor,
                constant: 8
            ).isActive = true

            // this is the important part :

            textField.bottomAnchor.constraint(
                equalTo: _inputAccessoryView.layoutMarginsGuide.bottomAnchor,
                constant: -8
            ).isActive = true
        }

        return _inputAccessoryView
    }

    override func loadView() {

        let tableView = UITableView()
        tableView.keyboardDismissMode = .interactive

        view = tableView
    }
}

class CustomView: UIView {

    // this is needed so that the inputAccesoryView is properly sized from the auto layout constraints
    // actual value is not important

    override var intrinsicContentSize: CGSize {
        return CGSize.zero
    }
}

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

API error: <_UIKBCompatInputView: 0x7fc725f20520; frame = (0 0; 0 0); layer = <CALayer: 0x60000232e6c0>> returned 0 width, assuming UIViewNoIntrinsicMetric

Я пытался переопределить intrinsicContentSize ненулевым значением, например CGSize(width: 50, height: 50), но все еще получаю эту ошибку. Как я могу решить эту проблему?


person user784637    schedule 18.12.2019    source источник


Ответы (1)


Это происходит потому, что у вас есть все ограничения required, но изначально возвращается внутренний размер zero. Таким образом, система макета пытается разместить ваше представление с нулевым размером, не может удовлетворить ваши ограничения, поэтому нарушает размер текстового поля. Самый простой (может быть, лучший?) способ исправить это — уменьшить приоритет ваших ограничений до значения чуть меньше required, чтобы система могла временно их нарушить.

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

class CustomView: UIView {

  private let textField = UITextField(frame: .zero)

  init(frame: CGRect) {
    backgroundColor = .groupTableViewBackground

    // do your textfield setup here
    addSubview(textField)
    textField.translatesAutoresizingMaskIntoConstraints = false
    textField.borderStyle = .roundedRect

    // set up your constraints
    let constraints: [NSLayoutConstraint] = [
      textField.topAnchor.constraint(equalTo: topAnchor, constant: 8),
      textField.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8),
      textField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
      textField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8),
    ]

    // slightly reduce the priority of all of your constraints
    constraints.forEach { $0.priority = UILayoutPriority(rawValue: 999) }

    // activate them
    NSLayoutConstraint.activate(constraints)
  }
}

Теперь в вашем контроллере представления вам просто нужно объявить вспомогательное представление как:

override var inputAccessoryView = CustomView()

Нет необходимости в частном хранилище, неявно развернутых опциях и т. д.

person Procrastin8    schedule 24.12.2019
comment
Спасибо за предложение - я пошел дальше и уменьшил приоритет ограничений, но все равно получаю ту же ошибку. - person user784637; 27.12.2019