【Swift】CollectionViewで選択中のセルを強調させる方法

2022.11.28

CollectionViewで選択中のセルを強調させたかったのでその方法について調べました。

環境

  • Xcode 14.1
  • iOS 16.1

はじめに

今回は選択中のセルを強調させるという内容になっている為、UICollectionViewの設定方法などは記載しておりません。

selectedBackgroundViewを使用する

UICollectionViewCellselectedBackgroundViewというプロパティを持っており、このプロパティは、セルが選択されるとセル自身のBackground Viewの上に表示されるViewです。

使用例

UserCell

import UIKit

class UserCell: UICollectionViewCell {

    func setup() {
        self.layer.masksToBounds = true
        self.layer.cornerRadius = self.layer.frame.height / 2

        // セルの背景色を設定
        self.backgroundColor = .systemGray5

        // セルが選択された時に表示するBackgroundViewを作成
        let selectedBackgroundView = UIView()
        selectedBackgroundView.backgroundColor = .systemYellow
        // 作成したBackgroundViewをセルが選択された時のViewに設定
        self.selectedBackgroundView = selectedBackgroundView
    }
}

ViewController: UICollectionViewDataSource

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UserCell",
                                                        for: indexPath) as? UserCell
    else { fatalError() }
    cell.setup()
    return cell
}

デモ

selected-collection-view-cell-1

ただし、この方法だとセル自身の背景Viewの上にselectedBackgroundViewを重ねて表示させている為、イメージが不透明の場合だとselectedBackgroundViewに切り替わったとしても選択中の色を確認することが出来ません。

また、セル全体のselectedBackgroundViewになる為、画像とユーザー名があるようなセルで、画像の部分だけ強調をさせたい時には不向きに感じました。

isSelectedの値の変更時に独自の選択Viewの状態を切り替える

これまではselectedBackgroundViewを表示するやり方でしたが、今回は選択状態を切り替えるViewを作成し、UICollectionViewCellisSelectedの値の変化時にその選択状態を切り替えるViewの状態を変更する方法です。

使用例

UserProfileCell

セルの中に、選択状態を表現する為のProfileImageFrameViewとユーザー画像用のUIImageView、ユーザー名用のUILabelがあります。

import UIKit

class UserProfileCell: UICollectionViewCell {

    @IBOutlet weak var profileImageFrameView: UIView!

    private let selectedFrameColor: CGColor = UIColor.tintColor.cgColor
    private let defaultFrameColor: CGColor = UIColor.systemGray5.cgColor

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override var isSelected: Bool {
        didSet {
            // 選択状態が切り替わった時に実行される
            self.profileImageFrameView.layer.borderColor = isSelected ? selectedFrameColor : defaultFrameColor
        }
    }

    func setup() {
        profileImageFrameView.layer.borderWidth = 1
        profileImageFrameView.layer.borderColor = defaultFrameColor
        profileImageFrameView.layer.cornerRadius = profileImageFrameView.layer.frame.height / 2
    }
}

isSelectedUICollectionViewCellの選択状態のプロパティで、セルが選択されるとこの値が変更されます。なので、didSetで値が変更された際に、選択中ならばprofileImageFrameViewborderColorを選択中のカラーに変更し、選択されていない場合はデフォルトのborderColorを設定しています。

ViewController: UICollectionViewDataSource

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UserProfileCell",
                                                        for: indexPath) as? UserProfileCell
    else { fatalError() }
    cell.setup()
    return cell
}

デモ

selected-collection-view-cell-3

おわりに

UICollectionViewCellを選択状態によって、見た目を変更することが出来ました。isSelectedだけではなく、isHighlightedというハイライト状態も取得できる為、ハイライトされている時も見た目を変更するのは良いかもしれません。

まだ他に選択状態を変更する良い方法あれば教えていただければと思います。

この記事が誰かの助けになれば嬉しいです。

参考