# CollectionViewChatLayout

    open class CollectionViewChatLayout : UICollectionViewLayout

A collection view layout designed to display items in a grid similar to `UITableView`, while aligning them to the leading or trailing edge of the `UICollectionView`. This layout facilitates chat-like behavior by maintaining a constant content offset from the bottom. Additionally, it is capable of handling autosizing cells and supplementary views.

### Custom Properties:

`CollectionViewChatLayout.delegate`

`CollectionViewChatLayout.settings`

`CollectionViewChatLayout.keepContentOffsetAtBottomOnBatchUpdates`

`CollectionViewChatLayout.processOnlyVisibleItemsOnAnimatedBatchUpdates`

`CollectionViewChatLayout.visibleBounds`

`CollectionViewChatLayout.layoutFrame`

### Custom Methods:

`CollectionViewChatLayout.getContentOffsetSnapshot(...)`

`CollectionViewChatLayout.restoreContentOffset(...)`

### Custom Properties

- `delegate`

  `CollectionViewChatLayout` delegate.

  #### Declaration

  Swift

      open weak var delegate: ChatLayoutDelegate?

- `settings`

  Additional settings for `CollectionViewChatLayout`.

  #### Declaration

  Swift

      public var settings: ChatLayoutSettings { get set }

- `keepContentOffsetAtBottomOnBatchUpdates`

  The default `UIScrollView` behaviour is to keep content offset constant from the top edge. If this flag is set to `true` `CollectionViewChatLayout` should try to compensate batch update changes to keep the current content at the bottom of the visible part of `UICollectionView`.

  NB: Keep in mind that if during the batch content inset changes also (e.g. keyboard frame changes), `CollectionViewChatLayout` will usually get that information after the animation starts and wont be able to compensate that change too. It should be done manually.

  #### Declaration

  Swift

      public var keepContentOffsetAtBottomOnBatchUpdates: Bool

- `keepContentAtBottomOfVisibleArea`

  The default behavior of UICollectionView is to maintain UICollectionViewCells at the top of the visible rectangle when the content size is smaller than the visible area. By setting the respective flag to true, this behavior can be reversed to achieve the result like in Telegram..

  #### Declaration

  Swift

      public var keepContentAtBottomOfVisibleArea: Bool

- `processOnlyVisibleItemsOnAnimatedBatchUpdates`

  tries to process only the elements that are currently visible on the screen. But often it is not needed. This flag allows you to have fine control over this behaviour. It set to `true` by default to keep the compatibility with the older versions of the library.

  NB: This flag is only to provide fine control over the batch updates. If in doubts - keep it `true`.

  #### Declaration

  Swift

      public var processOnlyVisibleItemsOnAnimatedBatchUpdates: Bool

- `supportSelfSizingInvalidation`

  A mode that enables automatic self-sizing invalidation after Auto Layout changes. It’s advisable to continue using the reload/reconfigure method, especially when multiple changes occur concurrently in an animated fashion. This approach ensures that the `CollectionViewChatLayout` can handle these changes while maintaining the content offset accurately. Consider using it when no better alternatives are available.

  NB: This is an experimental flag.

  #### Declaration

  Swift

      @available(iOS 16.0, *)
      public var supportSelfSizingInvalidation: Bool { get set }

- `visibleBounds`

  Represent the currently visible rectangle.

  #### Declaration

  Swift

      open var visibleBounds: CGRect { get }

- `layoutFrame`

  Represent the rectangle where all the items are aligned.

  #### Declaration

  Swift

      open var layoutFrame: CGRect { get }

### Inherited Properties

- `developmentLayoutDirection`

  The direction of the language you used when designing `CollectionViewChatLayout` layout.

  #### Declaration

  Swift

      open override var developmentLayoutDirection: UIUserInterfaceLayoutDirection { get }

- `flipsHorizontallyInOppositeLayoutDirection`

  A Boolean value that indicates whether the horizontal coordinate system is automatically flipped at appropriate times.

  #### Declaration

  Swift

      open override var flipsHorizontallyInOppositeLayoutDirection: Bool { get }

- `layoutAttributesClass`

  Custom layoutAttributesClass is `ChatLayoutAttributes`.

  #### Declaration

  Swift

      public override class var layoutAttributesClass: AnyClass { get }

- `invalidationContextClass`

  Custom invalidationContextClass is `ChatLayoutInvalidationContext`.

  #### Declaration

  Swift

      public override class var invalidationContextClass: AnyClass { get }

- `collectionViewContentSize`

  The width and height of the collection view’s contents.

  #### Declaration

  Swift

      open override var collectionViewContentSize: CGSize { get }

- `enableIOS15_1Fix`

  There is an issue in IOS 15.1 that proposed content offset is being ignored by the UICollectionView when user is scrolling. This flag enables a hack to compensate this offset later. You can disable it if necessary. Bug reported: https://feedbackassistant.apple.com/feedback/9727104

  PS: This issue was fixed in 15.2

  #### Declaration

  Swift

      public var enableIOS15_1Fix: Bool

### Constructors

- `init(flipsHorizontallyInOppositeLayoutDirection:)`

  Default constructor.

  #### Declaration

  Swift

      public init(flipsHorizontallyInOppositeLayoutDirection: Bool = true)

  #### Parameters

  `flipsHorizontallyInOppositeLayoutDirection` | Indicates whether the horizontal coordinate system is automatically flipped at appropriate times. In practice, this is used to support right-to-left layout.

- `init(coder:)`

  Returns an object initialized from data in a given unarchiver.

  #### Declaration

  Swift

      public required init?(coder aDecoder: NSCoder)

### Custom Methods

- `getContentOffsetSnapshot(from:)`

  Get current offset of the item closest to the provided edge.

  #### Declaration

  Swift

      open func getContentOffsetSnapshot(from edge: ChatLayoutPositionSnapshot.Edge) -> ChatLayoutPositionSnapshot?

  #### Parameters

  `edge` | The edge of the `UICollectionView`

  #### Return Value

  `ChatLayoutPositionSnapshot`

- `restoreContentOffset(with:)`

  Invalidates layout of the `UICollectionView` and trying to keep the offset of the item provided in `ChatLayoutPositionSnapshot`

  #### Declaration

  Swift

      open func restoreContentOffset(with snapshot: ChatLayoutPositionSnapshot)

  #### Parameters

  `snapshot` | `ChatLayoutPositionSnapshot`

- `reconfigureItems(at:)`

  If you want to use new `UICollectionView.reconfigureItems(..)` api and expect the reconfiguration to happen animated as well

  - you must call this method next to the `UICollectionView` one. `UIKit` in its classic way uses private API to process it.

  NB: Reconfigure items is not exposed to the layout, it may behave strange and if you experience something like this - move to the `UICollectionView.reloadItems(..)` as a safer option.

  #### Declaration

  Swift

      open func reconfigureItems(at indexPaths: [IndexPath])

### Providing Layout Attributes

- `prepare()`

  Tells the layout object to update the current layout.

  #### Declaration

  Swift

      open override func prepare()

- `layoutAttributesForElements(in:)`

  Retrieves the layout attributes for all of the cells and views in the specified rectangle.

  #### Declaration

  Swift

      open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?

- `layoutAttributesForItem(at:)`

  Retrieves layout information for an item at the specified index path with a corresponding cell.

  #### Declaration

  Swift

      open override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?

- `layoutAttributesForSupplementaryView(ofKind:at:)`

  Retrieves the layout attributes for the specified supplementary view.

  #### Declaration

  Swift

      open override func layoutAttributesForSupplementaryView(ofKind elementKind: String,
                                                              at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?

### Coordinating Animated Changes

- `prepare(forAnimatedBoundsChange:)`

  Prepares the layout object for animated changes to the view’s bounds or the insertion or deletion of items.

  #### Declaration

  Swift

      open override func prepare(forAnimatedBoundsChange oldBounds: CGRect)

- `finalizeAnimatedBoundsChange()`

  Cleans up after any animated changes to the view’s bounds or after the insertion or deletion of items.

  #### Declaration

  Swift

      open override func finalizeAnimatedBoundsChange()

### Context Invalidation

- `shouldInvalidateLayout(forPreferredLayoutAttributes:withOriginalAttributes:)`

  Asks the layout object if changes to a self-sizing cell require a layout update.

  #### Declaration

  Swift

      open override func shouldInvalidateLayout(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes,
                                                withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> Bool

- `invalidationContext(forPreferredLayoutAttributes:withOriginalAttributes:)`

  Retrieves a context object that identifies the portions of the layout that should change in response to dynamic cell changes.

  #### Declaration

  Swift

      open override func invalidationContext(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes,
                                             withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutInvalidationContext

- `shouldInvalidateLayout(forBoundsChange:)`

  Asks the layout object if the new bounds require a layout update.

  #### Declaration

  Swift

      open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool

- `invalidationContext(forBoundsChange:)`

  Retrieves a context object that defines the portions of the layout that should change when a bounds change occurs.

  #### Declaration

  Swift

      open override func invalidationContext(forBoundsChange newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext

- `invalidateLayout(with:)`

  Invalidates the current layout using the information in the provided context object.

  #### Declaration

  Swift

      open override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext)

- `invalidateLayout()`

  Invalidates the current layout and triggers a layout update.

  #### Declaration

  Swift

      open override func invalidateLayout()

- `targetContentOffset(forProposedContentOffset:)`

  Retrieves the content offset to use after an animated layout update or change.

  #### Declaration

  Swift

      open override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint

### Responding to Collection View Updates

- `prepare(forCollectionViewUpdates:)`

  Notifies the layout object that the contents of the collection view are about to change.

  #### Declaration

  Swift

      open override func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem])

- `finalizeCollectionViewUpdates()`

  Performs any additional animations or clean up needed during a collection view update.

  #### Declaration

  Swift

      open override func finalizeCollectionViewUpdates()

### Cell Appearance Animation

- `initialLayoutAttributesForAppearingItem(at:)`

  Retrieves the starting layout information for an item being inserted into the collection view.

  #### Declaration

  Swift

      open override func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?

- `finalLayoutAttributesForDisappearingItem(at:)`

  Retrieves the final layout information for an item that is about to be removed from the collection view.

  #### Declaration

  Swift

      open override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?

### Supplementary View Appearance Animation

- `initialLayoutAttributesForAppearingSupplementaryElement(ofKind:at:)`

  Retrieves the starting layout information for a supplementary view being inserted into the collection view.

  #### Declaration

  Swift

      open override func initialLayoutAttributesForAppearingSupplementaryElement(ofKind elementKind: String,
                                                                                 at elementIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?

- `finalLayoutAttributesForDisappearingSupplementaryElement(ofKind:at:)`

  Retrieves the final layout information for a supplementary view that is about to be removed from the collection view.

  #### Declaration

  Swift

      open override func finalLayoutAttributesForDisappearingSupplementaryElement(ofKind elementKind: String,
                                                                                  at elementIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?