Skip to content

Commit 3743433

Browse files
committed
Added processOnlyVisibleItemsOnAnimatedBatchUpdates for a finer control over animation process.
1 parent 1e9776c commit 3743433

File tree

78 files changed

+2247
-2082
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+2247
-2082
lines changed

.jazzy.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ custom_categories:
1717
- ChatLayoutInvalidationContext
1818
- ItemKind
1919
- ItemSize
20-
- ItemSize.CaseType
2120
- ChatItemAlignment
2221
- InitialAttributesRequestType
2322

ChatLayout.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'ChatLayout'
3-
s.version = '1.2.13'
3+
s.version = '1.2.14'
44
s.summary = 'Chat UI Library. It uses custom UICollectionViewLayout to provide you full control over the presentation.'
55
s.swift_version = '5.7'
66

ChatLayout/Classes/Core/CollectionViewChatLayout.swift

+11
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import UIKit
2323
///
2424
/// `CollectionViewChatLayout.keepContentOffsetAtBottomOnBatchUpdates`
2525
///
26+
/// `CollectionViewChatLayout.processOnlyVisibleItemsOnAnimatedBatchUpdates`
27+
///
2628
/// `CollectionViewChatLayout.visibleBounds`
2729
///
2830
/// `CollectionViewChatLayout.layoutFrame`
@@ -58,6 +60,15 @@ public final class CollectionViewChatLayout: UICollectionViewLayout {
5860
/// the animation starts and wont be able to compensate that change too. It should be done manually.
5961
public var keepContentOffsetAtBottomOnBatchUpdates: Bool = false
6062

63+
/// Sometimes `UIScrollView` can behave weirdly if there are too many corrections in it's `contentOffset` during the animation. Especially when content size of the `UIScrollView`
64+
// is getting smaller first and then expands again as the newly appearing cells sizes are being calculated. That is why `CollectionViewChatLayout`
65+
/// 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.
66+
/// It set to `true` by default to keep the compatibility with the older versions of the library.
67+
///
68+
/// **NB:**
69+
/// This flag is only to provide fine control over the batch updates. If in doubts - keep it `true`.
70+
public var processOnlyVisibleItemsOnAnimatedBatchUpdates: Bool = true
71+
6172
/// Represent the currently visible rectangle.
6273
public var visibleBounds: CGRect {
6374
guard let collectionView = collectionView else {

ChatLayout/Classes/Core/Model/StateController.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ protocol ChatLayoutRepresentation: AnyObject {
2828

2929
var keepContentOffsetAtBottomOnBatchUpdates: Bool { get }
3030

31+
var processOnlyVisibleItemsOnAnimatedBatchUpdates: Bool { get }
32+
3133
func numberOfItems(in section: Int) -> Int
3234

3335
func configuration(for element: ItemKind, at indexPath: IndexPath) -> ItemModel.Configuration
@@ -764,7 +766,7 @@ final class StateController<Layout: ChatLayoutRepresentation> {
764766
let itemPath = ItemPath(item: itemIndex, section: sectionIndex)
765767
if let itemFrame = itemFrame(for: itemPath, kind: .cell, at: state, isFinal: true, additionalAttributes: additionalAttributes),
766768
check(rect: itemFrame) {
767-
if state == .beforeUpdate || isAnimatedBoundsChange {
769+
if state == .beforeUpdate || isAnimatedBoundsChange || !layoutRepresentation.processOnlyVisibleItemsOnAnimatedBatchUpdates {
768770
allRects.append((frame: itemFrame, indexPath: itemPath, kind: .cell))
769771
} else {
770772
var itemWasVisibleBefore: Bool {

ChatLayout/Classes/Extras/EdgeAligningView.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ public final class EdgeAligningView<CustomView: UIView>: UIView {
147147
let layoutConstraint = view.centerXAnchor.constraint(equalTo: layoutMarginsGuide.centerXAnchor)
148148
addedConstraints.append(layoutConstraint)
149149
layoutConstraint.isActive = true
150-
} else if flexibleEdges.contains(.top), flexibleEdges.contains(.bottom) {
150+
}
151+
if flexibleEdges.contains(.top), flexibleEdges.contains(.bottom) {
151152
let layoutConstraint = view.centerYAnchor.constraint(equalTo: layoutMarginsGuide.centerYAnchor)
152153
addedConstraints.append(layoutConstraint)
153154
layoutConstraint.isActive = true

Example/ChatLayout/Chat/Controller/ChatControllerDelegate.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ import Foundation
1414

1515
protocol ChatControllerDelegate: AnyObject {
1616

17-
func update(with sections: [Section])
17+
func update(with sections: [Section], requiresIsolatedProcess: Bool)
1818

1919
}

Example/ChatLayout/Chat/Controller/DefaultChatController.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,9 @@ final class DefaultChatController: ChatController {
193193
}
194194
}
195195

196-
private func repopulateMessages() {
196+
private func repopulateMessages(requiresIsolatedProcess: Bool = false) {
197197
propagateLatestMessages { sections in
198-
self.delegate?.update(with: sections)
198+
self.delegate?.update(with: sections, requiresIsolatedProcess: requiresIsolatedProcess)
199199
}
200200
}
201201

@@ -305,7 +305,7 @@ extension DefaultChatController: EditingAccessoryControllerDelegate {
305305

306306
func deleteMessage(with id: UUID) {
307307
messages = Array(messages.filter { $0.id != id })
308-
repopulateMessages()
308+
repopulateMessages(requiresIsolatedProcess: true)
309309
}
310310

311311
}

Example/ChatLayout/Chat/View/ChatViewController.swift

+17-7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ final class ChatViewController: UIViewController {
3232
case scrollingToBottom
3333
case showingPreview
3434
case showingAccessory
35+
case updatingCollectionInIsolation
3536
}
3637

3738
private enum ControllerActions {
@@ -124,6 +125,7 @@ final class ChatViewController: UIViewController {
124125
chatLayout.settings.interSectionSpacing = 8
125126
chatLayout.settings.additionalInsets = UIEdgeInsets(top: 8, left: 5, bottom: 8, right: 5)
126127
chatLayout.keepContentOffsetAtBottomOnBatchUpdates = true
128+
chatLayout.processOnlyVisibleItemsOnAnimatedBatchUpdates = false
127129

128130
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: chatLayout)
129131
view.addSubview(collectionView)
@@ -156,7 +158,7 @@ final class ChatViewController: UIViewController {
156158
currentControllerActions.options.insert(.loadingInitialMessages)
157159
chatController.loadInitialMessages { sections in
158160
self.currentControllerActions.options.remove(.loadingInitialMessages)
159-
self.processUpdates(with: sections, animated: true)
161+
self.processUpdates(with: sections, animated: true, requiresIsolatedProcess: false)
160162
}
161163

162164
KeyboardListener.shared.add(delegate: self)
@@ -298,7 +300,7 @@ extension ChatViewController: UIScrollViewDelegate {
298300
}
299301
// Reloading the content without animation just because it looks better is the scrolling is in process.
300302
let animated = !self.isUserInitiatedScrolling
301-
self.processUpdates(with: sections, animated: animated) {
303+
self.processUpdates(with: sections, animated: animated, requiresIsolatedProcess: false) {
302304
self.currentControllerActions.options.remove(.loadingPreviousMessages)
303305
}
304306
}
@@ -441,11 +443,11 @@ extension ChatViewController: UICollectionViewDelegate {
441443

442444
extension ChatViewController: ChatControllerDelegate {
443445

444-
func update(with sections: [Section]) {
445-
processUpdates(with: sections, animated: true)
446+
func update(with sections: [Section], requiresIsolatedProcess: Bool) {
447+
processUpdates(with: sections, animated: true, requiresIsolatedProcess: requiresIsolatedProcess)
446448
}
447449

448-
private func processUpdates(with sections: [Section], animated: Bool = true, completion: (() -> Void)? = nil) {
450+
private func processUpdates(with sections: [Section], animated: Bool = true, requiresIsolatedProcess: Bool, completion: (() -> Void)? = nil) {
449451
guard isViewLoaded else {
450452
dataSource.sections = sections
451453
return
@@ -459,7 +461,7 @@ extension ChatViewController: ChatControllerDelegate {
459461
guard let self = self else {
460462
return
461463
}
462-
self.processUpdates(with: sections, animated: animated, completion: completion)
464+
self.processUpdates(with: sections, animated: animated, requiresIsolatedProcess: requiresIsolatedProcess, completion: completion)
463465
})
464466
currentInterfaceActions.add(reaction: reaction)
465467
return
@@ -475,6 +477,10 @@ extension ChatViewController: ChatControllerDelegate {
475477
return
476478
}
477479

480+
if requiresIsolatedProcess {
481+
chatLayout.processOnlyVisibleItemsOnAnimatedBatchUpdates = true
482+
currentInterfaceActions.options.insert(.updatingCollectionInIsolation)
483+
}
478484
currentControllerActions.options.insert(.updatingCollection)
479485
collectionView.reload(using: changeSet,
480486
interrupt: { changeSet in
@@ -491,6 +497,10 @@ extension ChatViewController: ChatControllerDelegate {
491497
},
492498
completion: { _ in
493499
DispatchQueue.main.async {
500+
self.chatLayout.processOnlyVisibleItemsOnAnimatedBatchUpdates = false
501+
if requiresIsolatedProcess {
502+
self.currentInterfaceActions.options.remove(.updatingCollectionInIsolation)
503+
}
494504
completion?()
495505
self.currentControllerActions.options.remove(.updatingCollection)
496506
}
@@ -595,7 +605,7 @@ extension ChatViewController: InputBarAccessoryViewDelegate {
595605
self.scrollToBottom(completion: {
596606
self.chatController.sendMessage(.text(messageText)) { sections in
597607
self.currentInterfaceActions.options.remove(.sendingMessage)
598-
self.processUpdates(with: sections, animated: true)
608+
self.processUpdates(with: sections, animated: true, requiresIsolatedProcess: false)
599609
}
600610
})
601611
}

Example/Podfile.lock

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
PODS:
2-
- ChatLayout (1.2.13):
3-
- ChatLayout/Ultimate (= 1.2.13)
4-
- ChatLayout/Core (1.2.13)
5-
- ChatLayout/Extras (1.2.13):
2+
- ChatLayout (1.2.14):
3+
- ChatLayout/Ultimate (= 1.2.14)
4+
- ChatLayout/Core (1.2.14)
5+
- ChatLayout/Extras (1.2.14):
66
- ChatLayout/Core
7-
- ChatLayout/Ultimate (1.2.13):
7+
- ChatLayout/Ultimate (1.2.14):
88
- ChatLayout/Core
99
- ChatLayout/Extras
1010
- DifferenceKit (1.3.0):
@@ -35,7 +35,7 @@ EXTERNAL SOURCES:
3535
:path: "../"
3636

3737
SPEC CHECKSUMS:
38-
ChatLayout: c37e188edd9a922d4c19d259703a29c63e0d18c6
38+
ChatLayout: 0dabcfbceffa95f2a9a11c3bed1439457f89bc77
3939
DifferenceKit: ab185c4d7f9cef8af3fcf593e5b387fb81e999ca
4040
FPSCounter: 884afec377de66637808c4f52ecc3b85a404732b
4141
InputBarAccessoryView: 1d7b0a672b36e370f01f264b3907ef39d03328e3

Example/Tests/MockCollectionLayout.swift

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class MockCollectionLayout: ChatLayoutRepresentation, ChatLayoutDelegate {
4545

4646
let keepContentOffsetAtBottomOnBatchUpdates: Bool = true
4747

48+
let processOnlyVisibleItemsOnAnimatedBatchUpdates: Bool = true
49+
4850
func numberOfItems(in section: Int) -> Int {
4951
numberOfItemsInSection[section] ?? 0
5052
}

docs/Classes/CellLayoutContainerView.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<header class="header">
2222
<p class="header-col header-col--primary">
2323
<a class="header-link" href="../index.html">
24-
ChatLayout 1.2.13 Docs
24+
ChatLayout 1.2.14 Docs
2525
</a>
2626
(100% documented)
2727
</p>
@@ -455,7 +455,7 @@ <h4>Parameters</h4>
455455
</article>
456456
</div>
457457
<section class="footer">
458-
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-02)</p>
458+
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-04)</p>
459459
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
460460
</section>
461461
</body>

docs/Classes/ChatLayoutAttributes.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<header class="header">
2222
<p class="header-col header-col--primary">
2323
<a class="header-link" href="../index.html">
24-
ChatLayout 1.2.13 Docs
24+
ChatLayout 1.2.14 Docs
2525
</a>
2626
(100% documented)
2727
</p>
@@ -414,7 +414,7 @@ <h4>Declaration</h4>
414414
</article>
415415
</div>
416416
<section class="footer">
417-
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-02)</p>
417+
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-04)</p>
418418
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
419419
</section>
420420
</body>

docs/Classes/ChatLayoutInvalidationContext.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<header class="header">
2222
<p class="header-col header-col--primary">
2323
<a class="header-link" href="../index.html">
24-
ChatLayout 1.2.13 Docs
24+
ChatLayout 1.2.14 Docs
2525
</a>
2626
(100% documented)
2727
</p>
@@ -199,7 +199,7 @@ <h4>Declaration</h4>
199199
</article>
200200
</div>
201201
<section class="footer">
202-
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-02)</p>
202+
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-04)</p>
203203
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
204204
</section>
205205
</body>

docs/Classes/CollectionViewChatLayout.html

+35-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<header class="header">
2222
<p class="header-col header-col--primary">
2323
<a class="header-link" href="../index.html">
24-
ChatLayout 1.2.13 Docs
24+
ChatLayout 1.2.14 Docs
2525
</a>
2626
(100% documented)
2727
</p>
@@ -165,6 +165,8 @@ <h3 id='custom-properties' class='heading'>Custom Properties:</h3>
165165

166166
<p><code><a href="../Classes/CollectionViewChatLayout.html#/s:10ChatLayout014CollectionViewaB0C39keepContentOffsetAtBottomOnBatchUpdatesSbvp">CollectionViewChatLayout.keepContentOffsetAtBottomOnBatchUpdates</a></code></p>
167167

168+
<p><code><a href="../Classes/CollectionViewChatLayout.html#/s:10ChatLayout014CollectionViewaB0C45processOnlyVisibleItemsOnAnimatedBatchUpdatesSbvp">CollectionViewChatLayout.processOnlyVisibleItemsOnAnimatedBatchUpdates</a></code></p>
169+
168170
<p><code><a href="../Classes/CollectionViewChatLayout.html#/s:10ChatLayout014CollectionViewaB0C13visibleBoundsSo6CGRectVvp">CollectionViewChatLayout.visibleBounds</a></code></p>
169171

170172
<p><code><a href="../Classes/CollectionViewChatLayout.html#/s:10ChatLayout014CollectionViewaB0C11layoutFrameSo6CGRectVvp">CollectionViewChatLayout.layoutFrame</a></code></p>
@@ -277,6 +279,37 @@ <h4>Declaration</h4>
277279
</section>
278280
</div>
279281
</li>
282+
<li class="item">
283+
<div>
284+
<code>
285+
<a name="/s:10ChatLayout014CollectionViewaB0C45processOnlyVisibleItemsOnAnimatedBatchUpdatesSbvp"></a>
286+
<a name="//apple_ref/swift/Property/processOnlyVisibleItemsOnAnimatedBatchUpdates" class="dashAnchor"></a>
287+
<a class="token" href="#/s:10ChatLayout014CollectionViewaB0C45processOnlyVisibleItemsOnAnimatedBatchUpdatesSbvp">processOnlyVisibleItemsOnAnimatedBatchUpdates</a>
288+
</code>
289+
</div>
290+
<div class="height-container">
291+
<div class="pointer-container"></div>
292+
<section class="section">
293+
<div class="pointer"></div>
294+
<div class="abstract">
295+
<p>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.
296+
It set to <code>true</code> by default to keep the compatibility with the older versions of the library.</p>
297+
298+
<p><strong>NB:</strong>
299+
This flag is only to provide fine control over the batch updates. If in doubts - keep it <code>true</code>.</p>
300+
301+
</div>
302+
<div class="declaration">
303+
<h4>Declaration</h4>
304+
<div class="language">
305+
<p class="aside-title">Swift</p>
306+
<pre class="highlight swift"><code><span class="kd">public</span> <span class="k">var</span> <span class="nv">processOnlyVisibleItemsOnAnimatedBatchUpdates</span><span class="p">:</span> <span class="kt">Bool</span></code></pre>
307+
308+
</div>
309+
</div>
310+
</section>
311+
</div>
312+
</li>
280313
<li class="item">
281314
<div>
282315
<code>
@@ -1306,7 +1339,7 @@ <h4>Declaration</h4>
13061339
</article>
13071340
</div>
13081341
<section class="footer">
1309-
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-02)</p>
1342+
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-04)</p>
13101343
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
13111344
</section>
13121345
</body>

docs/Classes/ContainerCollectionReusableView.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<header class="header">
2222
<p class="header-col header-col--primary">
2323
<a class="header-link" href="../index.html">
24-
ChatLayout 1.2.13 Docs
24+
ChatLayout 1.2.14 Docs
2525
</a>
2626
(100% documented)
2727
</p>
@@ -375,7 +375,7 @@ <h4>Parameters</h4>
375375
</article>
376376
</div>
377377
<section class="footer">
378-
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-02)</p>
378+
<p>&copy; 2022 <a class="link" href="https://github.com/ekazaev" target="_blank" rel="external noopener">Evgeny Kazaev</a>. All rights reserved. (Last updated: 2022-11-04)</p>
379379
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.14.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
380380
</section>
381381
</body>

0 commit comments

Comments
 (0)