@@ -112,6 +112,11 @@ public final class ChatLayout: UICollectionViewLayout {
112
112
return contentSize
113
113
}
114
114
115
+ /// There is an issue in IOS 15.1 that proposed content offset is being ignored by the UICollectionView when user is scrolling.
116
+ /// This flag enables a hack to compensate this offset later. You can disable it if necessary.
117
+ /// Bug reported: https://feedbackassistant.apple.com/feedback/9727104
118
+ public var enableIOS15_1Fix : Bool = true
119
+
115
120
// MARK: Internal Properties
116
121
117
122
var adjustedContentInset : UIEdgeInsets {
@@ -175,6 +180,12 @@ public final class ChatLayout: UICollectionViewLayout {
175
180
176
181
private let _flipsHorizontallyInOppositeLayoutDirection : Bool
177
182
183
+ // MARK: IOS 15.1 fix flags
184
+
185
+ private var needsIOS15_1IssueFix : Bool {
186
+ return enableIOS15_1Fix && isIOS15_1orHigher && isUserInitiatedScrolling && !controller. isAnimatedBoundsChange
187
+ }
188
+
178
189
// MARK: Constructors
179
190
180
191
/// Default constructor.
@@ -609,9 +620,16 @@ public final class ChatLayout: UICollectionViewLayout {
609
620
let collectionView = collectionView {
610
621
let minPossibleContentOffset = - collectionView. adjustedContentInset. top
611
622
let newProposedContentOffset = CGPoint ( x: proposedContentOffset. x, y: max ( minPossibleContentOffset, min ( proposedContentOffset. y + controller. proposedCompensatingOffset, maxPossibleContentOffset. y) ) )
612
- controller. proposedCompensatingOffset = 0
613
623
invalidationActions. formUnion ( [ . shouldInvalidateOnBoundsChange] )
614
- return newProposedContentOffset
624
+ if needsIOS15_1IssueFix {
625
+ // This fix affects performance as UICollectionView will request cells event though they wont be visible on the screen.
626
+ // It also causes a small flickering as content offset is being fixed at `finalizeCollectionViewUpdates` instead.
627
+ controller. batchUpdateCompensatingOffset += controller. proposedCompensatingOffset
628
+ return super. targetContentOffset ( forProposedContentOffset: proposedContentOffset)
629
+ } else {
630
+ controller. proposedCompensatingOffset = 0
631
+ return newProposedContentOffset
632
+ }
615
633
}
616
634
return super. targetContentOffset ( forProposedContentOffset: proposedContentOffset)
617
635
}
@@ -949,3 +967,12 @@ var isIOS13orHigher: Bool {
949
967
return false
950
968
}
951
969
}
970
+
971
+ @inline ( __always)
972
+ var isIOS15_1orHigher : Bool {
973
+ if #available( iOS 15 . 1 , * ) {
974
+ return true
975
+ } else {
976
+ return false
977
+ }
978
+ }
0 commit comments