質問編集履歴

1

ソースコードの追加

2021/01/29 10:50

投稿

popai306
popai306

スコア157

test CHANGED
File without changes
test CHANGED
@@ -10,15 +10,15 @@
10
10
 
11
11
  チャットメッセージを表示するための`ChatMessageCell`は`UILabel`+`AutoLayout`をつかっているため、
12
12
 
13
- 描画領域外のCellの高さを事前に計算できておらずスクロール時に描画計算するためスクロールがカクつく。
13
+ 描画領域外のCellの高さを事前に計算できておらずスクロール時に描画計算するためスクロールがカクつくのではないかと考えています
14
14
 
15
15
 
16
16
 
17
17
  ### 試したこと
18
18
 
19
- `UICollectionView`の`isPrefetchingEnabled`を`true`にすることで
19
+ `UICollectionView`の`isPrefetchingEnabled`を`true`にしましたが
20
-
20
+
21
- 多少スムーズにスクロールきるようになりましたがそれでもカクつきます
21
+ 改善はされませんでした。
22
22
 
23
23
 
24
24
 
@@ -97,3 +97,337 @@
97
97
  }
98
98
 
99
99
  ```
100
+
101
+
102
+
103
+ ```ChatMessageViewController
104
+
105
+
106
+
107
+ import UIKit
108
+
109
+
110
+
111
+ class ChatMessageViewController: UIViewController {
112
+
113
+
114
+
115
+ private var messages = [ChatThreadMessage]()
116
+
117
+ private var messageListener: ListenerRegistration?
118
+
119
+
120
+
121
+ enum Section { case main }
122
+
123
+ var messageCollectionDataSource: UICollectionViewDiffableDataSource<Section, ChatThreadMessage>! = nil
124
+
125
+ var currentMessageSnapShot = NSDiffableDataSourceSnapshot<Section, ChatThreadMessage>()
126
+
127
+
128
+
129
+ private let viewer: User
130
+
131
+ private let recipient: User
132
+
133
+
134
+
135
+ private let v: ChatMessageView
136
+
137
+ override func loadView() { view = v }
138
+
139
+
140
+
141
+ init(user: User, recipient: User) {
142
+
143
+ self.viewer = user
144
+
145
+ self.recipient = recipient
146
+
147
+
148
+
149
+ v = ChatMessageView()
150
+
151
+
152
+
153
+ super.init(nibName: nil, bundle: nil)
154
+
155
+ self.title = recipient.username
156
+
157
+ }
158
+
159
+
160
+
161
+ required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
162
+
163
+
164
+
165
+ override func viewDidLoad() {
166
+
167
+ super.viewDidLoad()
168
+
169
+
170
+
171
+ configDataSource()
172
+
173
+ configFirestore()
174
+
175
+ }
176
+
177
+ }
178
+
179
+
180
+
181
+ // MARK: - Helpers
182
+
183
+
184
+
185
+ extension ChatMessageViewController {
186
+
187
+ private func configDataSource() {
188
+
189
+ messageCollectionDataSource = UICollectionViewDiffableDataSource<Section, ChatThreadMessage> (collectionView: v.collectionView) {
190
+
191
+ [weak self] (collectionView: UICollectionView, indexPath: IndexPath, message: ChatThreadMessage) -> UICollectionViewCell? in
192
+
193
+ guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ChatMessageCell.reuseIdentifier,
194
+
195
+ for: indexPath) as? ChatMessageCell else { return nil }
196
+
197
+ cell.message.text = message.text
198
+
199
+ if message.senderId == self?.viewer.userId {
200
+
201
+ cell.applyOutcomingStyle()
202
+
203
+ } else {
204
+
205
+ cell.applyIncomingStyle()
206
+
207
+ }
208
+
209
+ return cell
210
+
211
+ }
212
+
213
+ currentMessageSnapShot.appendSections([.main])
214
+
215
+ }
216
+
217
+
218
+
219
+ private func configFirestore() {
220
+
221
+ var shouldAnimateScrolling = false
222
+
223
+
224
+
225
+ let chatRef = hoge
226
+
227
+ self.messageListener = chatRef.addSnapshotListener {[weak self] querySnapshot, error in
228
+
229
+ if let error = error {
230
+
231
+ print("(error.localizedDescription)")
232
+
233
+ return
234
+
235
+ }
236
+
237
+
238
+
239
+ guard let self = self, let snapshot = querySnapshot else { return }
240
+
241
+ snapshot.documentChanges.forEach { change in
242
+
243
+ if change.type == .added, let messageModel = try? change.document.data(as: ChatMessageModel.self) {
244
+
245
+ let chatMessage = ChatThreadMessage(model: messageModel)
246
+
247
+ self.currentMessageSnapShot.appendItems([chatMessage])
248
+
249
+ }
250
+
251
+ }
252
+
253
+
254
+
255
+ self.messageCollectionDataSource.apply(self.currentMessageSnapShot, animatingDifferences: false) {
256
+
257
+ [weak self] in
258
+
259
+ self?.scrollToBottom(animated: shouldAnimateScrolling)
260
+
261
+ shouldAnimateScrolling = true
262
+
263
+ }
264
+
265
+ }
266
+
267
+ }
268
+
269
+
270
+
271
+ private func scrollToBottom(animated: Bool = true) {
272
+
273
+ guard let bottomMessage = currentMessageSnapShot.itemIdentifiers.last,
274
+
275
+ let bottomIndexPath = messageCollectionDataSource.indexPath(for: bottomMessage) else { return }
276
+
277
+
278
+
279
+ self.v.collectionView.scrollToItem(at: bottomIndexPath, at: .bottom, animated: animated)
280
+
281
+ }
282
+
283
+ }
284
+
285
+
286
+
287
+ struct ChatThreadMessage: Hashable {
288
+
289
+ let text: String
290
+
291
+ let senderId: String
292
+
293
+ let senderUsername: String
294
+
295
+ let createdAt: Date
296
+
297
+
298
+
299
+ init(model: ChatMessageModel) {
300
+
301
+ text = model.content
302
+
303
+ senderId = model.senderId
304
+
305
+ senderUsername = model.senderUsername
306
+
307
+ createdAt = model.createdAt?.dateValue() ?? Date()
308
+
309
+ }
310
+
311
+ }
312
+
313
+ ```
314
+
315
+
316
+
317
+ ```ChatMessageView
318
+
319
+ import UIKit
320
+
321
+
322
+
323
+ class ChatMessageView: UIView {
324
+
325
+
326
+
327
+ var collectionView: UICollectionView! = nil
328
+
329
+
330
+
331
+ init() {
332
+
333
+ super.init(frame: .zero)
334
+
335
+ cofigHierarchy()
336
+
337
+ configConstraint()
338
+
339
+ }
340
+
341
+
342
+
343
+ required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
344
+
345
+ }
346
+
347
+
348
+
349
+ extension NChatThreadView {
350
+
351
+ private func cofigHierarchy() {
352
+
353
+ collectionView = UICollectionView(frame: .zero, collectionViewLayout: createLayout())
354
+
355
+ collectionView.isPrefetchingEnabled = true
356
+
357
+
358
+
359
+ collectionView.contentInset.top = 10
360
+
361
+
362
+
363
+ collectionView.register(ChatMessageCell.self, forCellWithReuseIdentifier: ChatMessageCell.reuseIdentifier)
364
+
365
+ addSubview(collectionView)
366
+
367
+ }
368
+
369
+
370
+
371
+ private func configConstraint() {
372
+
373
+ collectionView.translatesAutoresizingMaskIntoConstraints = false
374
+
375
+ NSLayoutConstraint.activate([
376
+
377
+ collectionView.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor),
378
+
379
+ collectionView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
380
+
381
+ collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
382
+
383
+ collectionView.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor)
384
+
385
+ ])
386
+
387
+ }
388
+
389
+
390
+
391
+ private func createLayout() -> UICollectionViewLayout {
392
+
393
+ let sectionProvider = { (sectionIndex: Int,
394
+
395
+ layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
396
+
397
+
398
+
399
+ let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
400
+
401
+ heightDimension: .estimated(44))
402
+
403
+ let item = NSCollectionLayoutItem(layoutSize: size)
404
+
405
+ let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitem: item, count: 1)
406
+
407
+
408
+
409
+ let section = NSCollectionLayoutSection(group: group)
410
+
411
+ section.orthogonalScrollingBehavior = .none
412
+
413
+ section.interGroupSpacing = 10
414
+
415
+ section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 15,
416
+
417
+ bottom: 0, trailing: 15)
418
+
419
+ return section
420
+
421
+ }
422
+
423
+
424
+
425
+ return UICollectionViewCompositionalLayout(sectionProvider: sectionProvider)
426
+
427
+ }
428
+
429
+ }
430
+
431
+
432
+
433
+ ```