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:) 内に次の処理を加えれば良い。

  1. 前世の記憶を削除する
// 古い subview を削除
cell.contentView.subviews.forEach { subview in
        subview.removeFromSuperview()
}
  1. 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

掲載略

こちらで見れます

カテゴリー: Tips

hahnah

はーな Webエンジニア。モバイルアプリも少々。Elmが好き。

0件のコメント

コメントを残す

メールアドレスが公開されることはありません。