Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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のメソッドを利用するとセルの状態に応じて好きなように見た目をカスタマイズすることができます。

takehilo
iOSアプリ開発エンジニア note: https://note.mu/takehilo 個人開発アプリ: https://apple.co/2S9HRR4
uzabase
企業活動の意思決定を支える情報インフラの提供
https://www.uzabase.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした