photo credit: maholyoak Pallid Swift Jerusalem IL 2007_05_26_005.jpg via photopin (license)
問題
まえの記事 の実装で、スクロールするほど Cell が多い場合、 スクロールをすることで Cell の配置が変わってしまうという問題が実は発生する。
修正方法を探る
CollectoinViewController のcollectionView(_:cellForItemAt:)
メソッドについて挙動を確認してみて分かったことは、
indexPath
の Cell が表示されるときに呼ばれる
(作成時に呼ばれるものと勘違いしていた)dequeueReusableCell
メソッドで 再利用可能な Cell を取している
(そのままやんけ)
↓ 問題のcollectionView(_:cellForItemAt:)
メソッド
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CustomCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CustomCell
cell.contentView.backgroundColor = UIColor.yellow
return cell
}
dequeueReusableCell
メソッドで表示されなくなった Cell を使い回す実装になっているのだが、どうやら、Cell が前世の状態のまま使い回されるようだ。
そのため、前世の記憶(addSubview メソッドで加えられた チェックマークの view)がそのまま残っているというわけ。
なので、前世の記憶を一旦消して、現世のindexPath
に応じてチェックマークを付けたり付けなかったりすればよい。
修正概要
具体的には、collectionView(_:cellForItemAt:)
内に次の処理を加えれば良い。
- 前世の記憶を削除する
// 古い subview を削除
cell.contentView.subviews.forEach { subview in
subview.removeFromSuperview()
}
indexPath
に応じてチェックマークを付け直す
if CustomCell.shouldCellBeMarked(selectedItemAt: indexPath) {
cell.mark(selectedItemAt: indexPath)
} else {
cell.unmark(deselectedItemAt: indexPath)
}
該当のindexPath
の Cell にチェックマークを付け直すかどうかを判断するには
indexPath
に対するチェックマーク有無を記憶しておく必要があるので、CustomCell に static 変数として用意した。
static var checkmarkStates: [Bool]
上記に合わせてその他細かな変更もあるが、それについてはソースコードを参照していただきたい。
ソースコード
修正後のソースコードは以下のとおり。
CustomCell.swift
CollectionViewController.swift
ExtendedCollectionViewController.swift
掲載略
0件のコメント