Skip to content

Commit 9c7ae0b

Browse files
committed
Updated example
1 parent f11359a commit 9c7ae0b

File tree

5 files changed

+101
-8
lines changed

5 files changed

+101
-8
lines changed

ChatLayout/Classes/Core/CollectionViewChatLayout.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ open class CollectionViewChatLayout: UICollectionViewLayout {
332332

333333
/// Returns index path of currently pinned item.
334334
open func indexPathForItePinnedAt(_ pinningType: ChatItemPinningType) -> IndexPath? {
335-
return controller.pinnedIndexPaths[pinningType]?.current
335+
controller.pinnedIndexPaths[pinningType]?.current
336336
}
337337

338338
// MARK: Providing Layout Attributes

Example/ChatLayout.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
8585
607FACEC1AFB9204008FA782 /* StateControllerProcessUpdatesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* StateControllerProcessUpdatesTests.swift */; };
8686
65D4D44932474631D9677C50 /* Pods_ChatLayout_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FB56A5FF321AA24C456635 /* Pods_ChatLayout_Tests.framework */; };
87+
845D3CDE2E0EECB2008CEC21 /* DateSeparatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845D3CDD2E0EECAB008CEC21 /* DateSeparatorView.swift */; };
8788
D5A31E60E9BF6F8C13EDFDC5 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A31C93E56F2602C9BA605B /* PerformanceTests.swift */; };
8889
/* End PBXBuildFile section */
8990

@@ -182,6 +183,7 @@
182183
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
183184
607FACEB1AFB9204008FA782 /* StateControllerProcessUpdatesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateControllerProcessUpdatesTests.swift; sourceTree = "<group>"; };
184185
7878AA33F3C696DE4A57C8C1 /* Pods-ChatLayout_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ChatLayout_Tests.release.xcconfig"; path = "Target Support Files/Pods-ChatLayout_Tests/Pods-ChatLayout_Tests.release.xcconfig"; sourceTree = "<group>"; };
186+
845D3CDD2E0EECAB008CEC21 /* DateSeparatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSeparatorView.swift; sourceTree = "<group>"; };
185187
A7BC3E7EC6986752E73178A2 /* ChatLayout.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = ChatLayout.podspec; path = ../ChatLayout.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
186188
B20283D68C00BDE38B8AB8BE /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
187189
B520747F8C032C454221D1EC /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
@@ -361,6 +363,7 @@
361363
4504F3C924FA66F500385590 /* View */ = {
362364
isa = PBXGroup;
363365
children = (
366+
845D3CDC2E0EECA1008CEC21 /* Date Separator */,
364367
4504F3CA24FA66F500385590 /* ChatViewController.swift */,
365368
4504F3CB24FA66F500385590 /* Status View */,
366369
4504F3CD24FA66F500385590 /* Data Source */,
@@ -547,6 +550,14 @@
547550
path = Pods;
548551
sourceTree = "<group>";
549552
};
553+
845D3CDC2E0EECA1008CEC21 /* Date Separator */ = {
554+
isa = PBXGroup;
555+
children = (
556+
845D3CDD2E0EECAB008CEC21 /* DateSeparatorView.swift */,
557+
);
558+
path = "Date Separator";
559+
sourceTree = "<group>";
560+
};
550561
/* End PBXGroup section */
551562

552563
/* Begin PBXNativeTarget section */
@@ -756,6 +767,7 @@
756767
4504F41124FA66F600385590 /* FullCellContentBubbleController.swift in Sources */,
757768
4504F40D24FA66F600385590 /* TextMessageController.swift in Sources */,
758769
4504F3F924FA66F600385590 /* Cell.swift in Sources */,
770+
845D3CDE2E0EECB2008CEC21 /* DateSeparatorView.swift in Sources */,
759771
4504F42B24FA67F400385590 /* SceneDelegate.swift in Sources */,
760772
4504F40E24FA66F600385590 /* TextMessageView.swift in Sources */,
761773
4504F41224FA66F600385590 /* EditNotifier.swift in Sources */,

Example/ChatLayout/Chat/View/ChatViewController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ final class ChatViewController: UIViewController {
131131
chatLayout.settings.interItemSpacing = 8
132132
chatLayout.settings.interSectionSpacing = 8
133133
chatLayout.settings.additionalInsets = UIEdgeInsets(top: 8, left: 5, bottom: 8, right: 5)
134+
chatLayout.settings.pinnableItems = .cells
134135
chatLayout.keepContentOffsetAtBottomOnBatchUpdates = true
135136
chatLayout.processOnlyVisibleItemsOnAnimatedBatchUpdates = false
136137
chatLayout.keepContentAtBottomOfVisibleArea = true

Example/ChatLayout/Chat/View/Data Source/DefaultChatCollectionDataSource.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ typealias TextMessageCollectionCell = ContainerCollectionViewCell<MessageContain
1919
typealias URLCollectionCell = ContainerCollectionViewCell<MessageContainerView<EditingAccessoryView, MainContainerView<AvatarView, URLView, StatusView>>>
2020
typealias ImageCollectionCell = ContainerCollectionViewCell<MessageContainerView<EditingAccessoryView, MainContainerView<AvatarView, ImageView, StatusView>>>
2121
typealias TitleCollectionCell = ContainerCollectionViewCell<UILabel>
22+
typealias DateSeparatorCollectionCell = ContainerCollectionViewCell<DateSeparatorView>
2223
typealias UserTitleCollectionCell = ContainerCollectionViewCell<SwappingContainerView<EdgeAligningView<UILabel>, UIImageView>>
2324
typealias TypingIndicatorCollectionCell = ContainerCollectionViewCell<MessageContainerView<EditingAccessoryView, MainContainerView<AvatarPlaceholderView, TextMessageView, VoidViewFactory>>>
2425

@@ -56,6 +57,7 @@ final class DefaultChatCollectionDataSource: NSObject, ChatCollectionDataSource
5657
collectionView.register(ImageCollectionCell.self, forCellWithReuseIdentifier: ImageCollectionCell.reuseIdentifier)
5758
collectionView.register(TitleCollectionCell.self, forCellWithReuseIdentifier: TitleCollectionCell.reuseIdentifier)
5859
collectionView.register(UserTitleCollectionCell.self, forCellWithReuseIdentifier: UserTitleCollectionCell.reuseIdentifier)
60+
collectionView.register(DateSeparatorCollectionCell.self, forCellWithReuseIdentifier: DateSeparatorCollectionCell.reuseIdentifier)
5961
collectionView.register(TypingIndicatorCollectionCell.self, forCellWithReuseIdentifier: TypingIndicatorCollectionCell.reuseIdentifier)
6062
collectionView.register(TextTitleView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: TextTitleView.reuseIdentifier)
6163
collectionView.register(TextTitleView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: TextTitleView.reuseIdentifier)
@@ -173,13 +175,10 @@ final class DefaultChatCollectionDataSource: NSObject, ChatCollectionDataSource
173175
return cell
174176
}
175177

176-
private func createDateTitle(collectionView: UICollectionView, indexPath: IndexPath, alignment: ChatItemAlignment, title: String) -> TitleCollectionCell {
177-
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TitleCollectionCell.reuseIdentifier, for: indexPath) as! TitleCollectionCell
178-
cell.customView.preferredMaxLayoutWidth = (collectionView.collectionViewLayout as? CollectionViewChatLayout)?.layoutFrame.width ?? collectionView.frame.width
179-
cell.customView.text = title
180-
cell.customView.textColor = .gray
181-
cell.customView.numberOfLines = 0
182-
cell.customView.font = .preferredFont(forTextStyle: .caption2)
178+
private func createDateTitle(collectionView: UICollectionView, indexPath: IndexPath, alignment: ChatItemAlignment, title: String) -> DateSeparatorCollectionCell {
179+
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DateSeparatorCollectionCell.reuseIdentifier, for: indexPath) as! DateSeparatorCollectionCell
180+
cell.customView.labelView.preferredMaxLayoutWidth = (collectionView.collectionViewLayout as? CollectionViewChatLayout)?.layoutFrame.width ?? collectionView.frame.width
181+
cell.customView.labelView.text = title
183182
cell.contentView.layoutMargins = UIEdgeInsets(top: 2, left: 0, bottom: 2, right: 0)
184183
return cell
185184
}
@@ -318,6 +317,15 @@ extension DefaultChatCollectionDataSource: ChatLayoutDelegate {
318317
true
319318
}
320319

320+
func pinningTypeForItem(_ chatLayout: CollectionViewChatLayout,
321+
at indexPath: IndexPath) -> ChatItemPinningType? {
322+
let cell = sections[indexPath.section].cells[indexPath.item]
323+
guard case .date = cell else {
324+
return nil
325+
}
326+
return .top
327+
}
328+
321329
public func sizeForItem(_ chatLayout: CollectionViewChatLayout, of kind: ItemKind, at indexPath: IndexPath) -> ItemSize {
322330
switch kind {
323331
case .cell:
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//
2+
// ChatLayout
3+
// DateSeparatorView.swift
4+
// https://github.com/ekazaev/ChatLayout
5+
//
6+
// Created by Eugene Kazaev in 2020-2025.
7+
// Distributed under the MIT license.
8+
//
9+
// Become a sponsor:
10+
// https://github.com/sponsors/ekazaev
11+
//
12+
13+
import ChatLayout
14+
import Foundation
15+
import UIKit
16+
17+
final class DateSeparatorView: UIView, StaticViewFactory {
18+
private lazy var borderView = {
19+
let view = UIView()
20+
view.backgroundColor = .white
21+
view.frame = bounds.insetBy(dx: -5, dy: -5)
22+
view.layer.borderWidth = 1
23+
view.layer.borderColor = UIColor.gray.cgColor
24+
return view
25+
}()
26+
27+
private(set) lazy var labelView: UILabel = {
28+
let view = UILabel()
29+
view.textColor = .gray
30+
view.font = .preferredFont(forTextStyle: .caption2)
31+
return view
32+
}()
33+
34+
override init(frame: CGRect) {
35+
super.init(frame: frame)
36+
setupSubviews()
37+
}
38+
39+
required init?(coder: NSCoder) {
40+
super.init(coder: coder)
41+
setupSubviews()
42+
}
43+
44+
override func layoutSubviews() {
45+
super.layoutSubviews()
46+
borderView.layer.cornerRadius = min(bounds.width, bounds.height) / 2
47+
}
48+
49+
private func setupSubviews() {
50+
translatesAutoresizingMaskIntoConstraints = false
51+
insetsLayoutMarginsFromSafeArea = false
52+
layoutMargins = .zero
53+
addSubview(borderView)
54+
addSubview(labelView)
55+
56+
borderView.translatesAutoresizingMaskIntoConstraints = false
57+
NSLayoutConstraint.activate([
58+
borderView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
59+
borderView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
60+
borderView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
61+
borderView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)
62+
])
63+
64+
labelView.translatesAutoresizingMaskIntoConstraints = false
65+
NSLayoutConstraint.activate([
66+
labelView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor, constant: 5),
67+
labelView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor, constant: -5),
68+
labelView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor, constant: 5),
69+
labelView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor, constant: -5)
70+
])
71+
}
72+
}

0 commit comments

Comments
 (0)