Swift UICollectionView Ячейка отображается / прокручивается в представлении неправильно, когда скрывающая клавиатура анимация меняет нижнюю вставку - PullRequest
0 голосов
/ 13 июня 2019

Я создаю представление мессенджера в приложении iOs (Swift) с помощью UICollectionView внутри UIViewController.Я черпаю вдохновение из MessageKit, и мне удалось все правильно настроить с помощью простой динамической высоты ячейки.Когда я скрываю клавиатуру, а нижняя вставка представления коллекции уменьшается, а представление коллекции прокручивается вниз, логически перетаскивает ячейки в представление сверху (прокручивает вниз).Я не уверен, что это как-то конфликтует с анимацией, скрывающей клавиатуру, но если это вызывает прокрутку представления коллекции, и поэтому отображаются ячейки, которых не было в представлении, они выглядят не прокрученными, а с какой-то странной анимацией макета.,Это происходит только тогда, когда скрывается клавиатура && collectionView внизу.Пожалуйста, проверьте gif:

ссылку на gif

Построение всего на UITableView сработало, но я стремлюсь к представлению коллекции из-за будущих функций.Я попытался использовать даже фиксированную высоту ячейки в CollectionViewFlowDelegate, но это имеет тот же эффект, что и динамически вычисляемые высоты.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

Я устанавливаю вставку UICollectionView так же, как в MessageKit:

    private func requiredScrollViewBottomInset(forKeyboardFrame keyboardFrame: CGRect) -> CGFloat {
        let intersection = chatCollectionView.frame.intersection(keyboardFrame)
        if intersection.isNull || (chatCollectionView.frame.maxY - intersection.maxY) > 0.001 {
        messagesCollectionView.frame.maxY when dealing with undocked keyboards.
            return max(0, additionalBottomInset - automaticallyAddedBottomInset)
        } else {
            return max(0, intersection.height + additionalBottomInset - automaticallyAddedBottomInset)
        }
    }

    @objc private func handleKeyboardDidChangeState(_ notification: Notification) {
        guard !isMessagesControllerBeingDismissed else { return }
        guard let keyboardStartFrameInScreenCoords = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? CGRect else { return }
        guard !keyboardStartFrameInScreenCoords.isEmpty || UIDevice.current.userInterfaceIdiom != .pad else {
            // WORKAROUND for what seems to be a bug in iPad's keyboard handling in iOS 11: we receive an extra spurious frame change
            // notification when undocking the keyboard, with a zero starting frame and an incorrect end frame. The workaround is to
            // ignore this notification.
            return
        }
        guard let keyboardEndFrameInScreenCoords = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
        let keyboardEndFrame = view.convert(keyboardEndFrameInScreenCoords, from: view.window)
        let newBottomInset = requiredScrollViewBottomInset(forKeyboardFrame: keyboardEndFrame)
        let differenceOfBottomInset = newBottomInset - messageCollectionViewBottomInset
        if maintainPositionOnKeyboardFrameChanged && differenceOfBottomInset >/*!=*/ 0 {
            let contentOffset = CGPoint(x: chatCollectionView.contentOffset.x, y: chatCollectionView.contentOffset.y + differenceOfBottomInset)
            chatCollectionView.setContentOffset(contentOffset, animated: false)
        }
        messageCollectionViewBottomInset = newBottomInset
    }

    internal func requiredInitialScrollViewBottomInset() -> CGFloat {
        print("accessory view for initial bottom inset: \(inputAccessoryView)")
        guard let inputAccessoryView = inputAccessoryView else { return 0 }
        return max(0, inputAccessoryView.frame.height + additionalBottomInset - automaticallyAddedBottomInset)
    }

Поскольку я не мог найти какую-либо связанную тему, касающуюся этой прокрутки при скрытии клавиатуры, я не уверен, является ли это проблемой reusableCell или конфликтом анимации?

EDIT

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

open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return collectionView?.bounds.width != newBounds.width
    }

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

open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        invalidateLayout(with: invalidationContext(forBoundsChange: newBounds))
        return collectionView?.bounds.width != newBounds.width
    }

    open override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext {
        let context = super.invalidationContext(forBoundsChange: newBounds)
        guard let flowLayoutContext = context as? UICollectionViewFlowLayoutInvalidationContext else { return context }
        let indexes: [IndexPath] = (collectionView?.indexPathsForVisibleSupplementaryElements(ofKind: UICollectionView.elementKindSectionHeader))!
        print(indexes)
        flowLayoutContext.invalidateSupplementaryElements(ofKind: UICollectionView.elementKindSectionHeader, at: indexes)
        print(context.invalidatedSupplementaryIndexPaths)
        return flowLayoutContext
    }

Операторы печати четко указывают, что только заголовки недействительны, а для остальных я возвращаю false.Но он ведет себя точно так же, как в gif (см. Ссылку - к сожалению, у меня пока недостаточно высокая репутация, чтобы добавить ее прямо здесь).Спасибо за любые комментарии!

...