UIEdgeInsets различное поведение с переменной и жестко заданным значением

#ios #swift #uicollectionview #uikit

#iOS #swift #uicollectionview #uikit

Вопрос:

У меня есть UICollectionView ограничение по краям a UIViewController . Я хочу обновлять нижнюю вставку UICollectionView всякий раз, когда отображается клавиатура, чтобы не скрывать элементы внизу UICollectionView . С этой целью я настроил наблюдателя следующим образом:

  override func viewDidLoad() {
    super.viewDidLoad()

    ...

    NotificationCenter.default.addObserver(self, selector: #selector(keyboard(onScreen:)), name: UIResponder.keyboardDidShowNotification, object: nil)
}


@objc func keyboard(onScreen notification: Notification?) {
    let info = notification?.userInfo
    let value = info?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
    guard let keyboardHeight = value?.cgRectValue.size.height else { return }
    print("Keyboard height: (keyboardHeight)")             // This prints out 371.0
    
    // This does not change anything in the UI
    collectionView.contentInset.bottom = keyboardHeight
    collectionView.verticalScrollIndicatorInsets.bottom = keyboardHeight
    
    // This updates the UI correctly
    collectionView.contentInset.bottom = 371.0
    collectionView.verticalScrollIndicatorInsets.bottom = 371.0
}
 

keyboard Функция вызывается правильно всякий раз, когда появляется клавиатура, и она выводит правильную высоту, как указано в комментариях к приведенному выше коду.

Проблема в том, что если я установлю contentInset переменную, полученную с клавиатуры Notification , в пользовательском интерфейсе ничего не изменится. Если я жестко задам точно такое же значение (371.0), пользовательский интерфейс изменится так, как я этого хочу.

Вещи, которые я пробовал, пока безуспешно:

  • Сохранение значения keyboardHeight в переменной класса и установка contentInset для него.
  • Вызов layoutIfNeeded() и updateConstraints() включение collectionView .
  • Создание локальной копии keyboardHeight as let heightCopy = CGFloat(keyboardHeight) и установка для нее вставок.

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

ОБНОВЛЕНИЕ: в попытке обойти эту проблему я собирался настроить некоторую логику, чтобы решить, на какое жестко заданное значение установить вставку. Проблема в том, что если я оберну вызов collectionView.contentInset.bottom = 371.0 в оператор if, он больше не будет работать, даже если он выполняется. Чтобы уточнить:

 collectionView.contentInset.bottom = 371.0 // This updates the UI correctly 
 

В то время как:

 if (some statement that is true) { 
   print("if passed")
   collectionView.contentInset.bottom = 371.0
   print("insets set")
} 
 

не приводит к каким-либо изменениям в пользовательском интерфейсе, даже если операторы печати отображаются в выходных данных. Я чувствую, что схожу с ума здесь. Любые идеи будут высоко оценены!

ОБНОВЛЕНИЕ 2: если я добавлю вызов для прокрутки до конца UICollectionView после установки вставки, теперь он работает. Я до сих пор не понимаю, почему на это влияет то, устанавливаете ли вы для вставки жестко заданную константу, или почему важно, переносите ли вы вызов в какое-то условное выражение, но это решило проблему для меня, на случай, если кто-нибудь еще столкнется с этим!

Ответ №1:

Одна вещь, которую вы можете попробовать, это заменить

 UIResponder.keyboardDidShowNotification 
 

с

 UIResponder.keyboardWillChangeFrameNotification
 

потому keyboardWillChangeFrameNotification что это всегда даст вам правильный кадр клавиатуры.

и еще одна вещь, которую следует отметить, вы должны вычесть высоту клавиатуры с помощью SafeArea bottom:

    let bottomInset = keyboardHeight - view.safeAreaInsets.bottom
 

Комментарии:

1. К сожалению, это не решило проблему: (Еще одна вещь, которую я обнаружил, это то, что обертывание collectionView.contentInset.bottom = 371.0 в if-statement заставляет его не работать. Код «if [оператор, который является истинным] { collectionView.contentInset.bottom = 371.0 } не обновляет пользовательский интерфейс, но удаляет оператор if, и он работает. Аналогично в инструкции switch.