我正在UIViewController内的UICollectionView的帮助下,在iOs(Swift)应用程序中构建Messenger视图。我从MessageKit中汲取了灵感,并且能够通过简单的动态单元格高度正确地设置所有内容。当我隐藏键盘并在集合视图滚动到底部时减小集合视图的底部插入时,它会从逻辑上将单元格从顶部拖动到视图中(向下滚动)。我不确定它是否与键盘隐藏动画有某种冲突,但是如果这导致集合视图滚动到太多,因此显示了不在视图中的单元格,它们看起来就没有滚动,而是带有一些奇怪的布局动画。仅当隐藏键盘&& collectionView在底部时才会发生。请检查gif:
在UITableView上构建所有内容都可以,但是由于将来的功能,我的目标是收集视图。我试图在CollectionViewFlowDelegate中甚至使用固定的单元格高度,但其效果与动态计算的高度相同。
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
我正在以与MessageKit中相同的方式设置UICollectionView插入:
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问题或动画冲突?
编辑
因此,部分解决方案是仅在宽度变化时使布局无效,这将防止键盘在隐藏时使布局无效:
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中的行为完全相同(请参阅链接-不幸的是,我的声誉还不够高,无法直接在此处添加)。谢谢您的任何评论!