iOS
Swift
swift4

UICollectionViewのセルの強調・選択時にセルの見た目を変化させる

UICollectionViewには、セルの強調・選択状態を管理する仕組みが備わっています。

UICollectionViewDelegateプロトコルに用意されているメソッドを実装することで、セルが強調、選択された時にセルの見た目を変化させることができます。

本記事ではこれらのメソッドを実装し、強調・選択状態に合わせてセルの背景を変化させる例をご紹介したいと思います。

なお、本記事では説明に必要な箇所のコードのみ掲載しています。

ベースとなる実装については以下の記事を参照してください。

UICollectionViewを必要最低限のコードで実装してみる


セルの強調時に背景色を変化させる

ベースの実装では以下のように背景色が赤のセルが並んでいます。

image.png

これらのセルが強調状態になった時に、背景色が青に変化するようにしてみます。

はじめに、UICollectionViewDataSourceのcollectionView:cellForItemAt:メソッドの実装を以下のように修正します。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = .red

// 追加
let selectedBGView = UIView(frame: cell.frame)
selectedBGView.backgroundColor = .blue
cell.selectedBackgroundView = selectedBGView

return cell
}

セルのselectedBackgroundViewプロパティにUIViewを設定しておくと、該当のセルが強調・選択状態になったときにそのビューに置き換わります。

ここでは背景色が青のビューを設定し、セルが強調・選択された時に背景色が変化するようにしています。

続いて、UICollectionViewDelegateプロトコルを実装します。

セルの強調・選択状態に関わるのは以下のメソッド群です。

extension ViewController: UICollectionViewDelegate {

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
return false
}

func collectionView(_ collectionView: UICollectionView, shouldDeselectItemAt indexPath: IndexPath) -> Bool {
return false
}

func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return true
}

func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
print("Highlighted: \(indexPath)")
}

func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
print("Unhighlighted: \(indexPath)")
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected: \(indexPath)")
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
print("Deselected: \(indexPath)")
}
}

最初の3つは、セルの強調・選択・選択解除を許可するかどうかを指定するメソッドです。


  • collectionView:shouldSelectItemAt:

  • collectionView:shouldDeselectItemAt:

  • collectionView:shouldHighlightItemAt:

これらはデフォルトでtrueになるので、強調状態のみ有効にするためここではcollectionView:shouldHighlightItemAt:のみtrueを返しています。

後半の4つは、セルが強調・強調解除・選択・選択解除された時にセルをカスタマイズするためのメソッドです。

ここでは単にこれらのメソッドが呼ばれたかどうかを出力する処理を実装しています。

実行すると、以下のようにセルが強調(タップし続けている)状態のときだけ背景色が青に変わっています。

highlight.gif


セルの選択時に背景色を変化させる

今度はセルが選択状態になった時に背景色が青に変化するようにしてみます。

以下の3つのメソッドはデフォルトでtrueなので、このケースでは実装しなくても良いです。

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {

return true // 変更
}

func collectionView(_ collectionView: UICollectionView, shouldDeselectItemAt indexPath: IndexPath) -> Bool {
return true // 変更
}

func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return true
}

select.gif

セルをタップすると選択状態となり、背景色が青に変わります。

別のセルをタップすると、そのセルが選択状態になり、前のセルは選択状態が解除されて背景色が赤に戻ります。


強調状態を有効にしないと選択状態にならない?

以下のように強調状態は無効にして、選択状態のみ有効にしようとしたのですが、セルをタップしても選択状態になりませんでした。

選択状態のみ有効という指定はできないようです。

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {

return true
}

func collectionView(_ collectionView: UICollectionView, shouldDeselectItemAt indexPath: IndexPath) -> Bool {
return true
}

func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return false
}

highlight-off.gif


一度でも選択されたら背景色は青のままにする

ちょっとだけ応用。

セルが一度でも選択された背景色が青になったら、選択状態が解除されても青のままにするという実装をしてみます。

まず、UICollectionViewDataSourceの実装を元に戻します。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = .red
return cell
}

次に、UICollectionViewDelegateを以下のように実装します。

extension ViewController: UICollectionViewDelegate {

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = .blue
}
}

blue.gif

別のセルをタップした時に前のセルの選択状態は解除されていますが、背景色は青のままです。

このように、UICollectionViewDelegateのメソッドを利用するとセルの状態に応じて好きなように見た目をカスタマイズすることができます。