CollectionViewCellにチェックボックスをつけて選択状態を見えるようにする
タイトルのとおりです.最終的には簡単だったのですがそこにたどり着くまでにいろいろ面倒だったので書いておきます.
CollectionViewで写真アプリのようにして写真を表示,そしてそれを複数選択をするというViewを作りたかったのですがただ思いついたとおりにCellの隅にチェックボックスを置いてCellに選択されているかというプロパティをもたせてどのCellが選択されているかを判断しようとしたらCollectionViewのCellの再利用の機能のせいであるCellを選択したら画面の外の他のCellも選択状態になるということになりましてそれで悩んでいたのですが,
ViewControllerの方で配列で選択されているCellのindexPathを保持しておくといいというのを見つけてその通りに実装しようとしたらなんかいろいろ面倒でじゃあどうするか...
CollectionViewCellに元々selectedとかいうプロパティがあるではないか! CollectionViewにselectedがtrueになっているCellを保持している配列もあるらしいじゃん!
こんなに困って自分で実装しようとしたら元々あったらしく無駄足な感じがしましたが気を取り直して標準であるプロパティを使って実装してみました.
今回作ったサンプルはこんな感じです.

この茶色のViewをUIImageViewにして画像を入れるとアルバムっぽくなるかと思います.
実装の仕方 概要
まずチェックマークを新しいクラスを使って書いておきます(CheckBox).画像は使わずdrawRectで描画しています.
CustomCellを作ります.ここでCellに非選択状態のCheckBoxViewを貼り付けておきます.
そしてCellの選択状態に表示されるUICollectionViewCellのプロパティであるselectedbackgroundViewに選択状態(緑色)のCheckBoxViewを入れておきます.
ViewControllerにCollectionViewを入れるときにcollectionViewのプロパティにallowsMultipleSelection = trueとセットすることでCellの複数選択を許可するようにしましょう.
以外と簡単にできます.
まずCheckBoxView
import UIKit
class CheckBoxView: UIView {
var selected = false
init(frame: CGRect,selected: Bool) {
super.init(frame:frame)
self.selected = selected
self.backgroundColor = UIColor.clearColor()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func drawRect(rect: CGRect) {
let ovalColor:UIColor
let ovalFrameColor:UIColor
let checkColor:UIColor
let RectCheck = CGRectMake(5, 5, rect.width - 10, rect.height - 10)
if self.selected {
ovalColor = UIColor(red: 85/255, green: 185/255, blue: 1/255, alpha: 1)
ovalFrameColor = UIColor.blackColor()
checkColor = UIColor.whiteColor()
}else{
ovalColor = UIColor(red: 150/255, green: 150/255, blue: 150/255, alpha: 0.2)
ovalFrameColor = UIColor(red: 50/255, green: 50/255, blue: 50/255, alpha: 0.3)
checkColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5)
}
// 円 -------------------------------------
let oval = UIBezierPath(ovalInRect: RectCheck)
// 塗りつぶし色の設定
ovalColor.setFill()
// 内側の塗りつぶし
oval.fill()
//枠の色
ovalFrameColor.setStroke()
//枠の太さ
oval.lineWidth = 2
// 描画
oval.stroke()
let xx = RectCheck.origin.x
let yy = RectCheck.origin.y
let width = RectCheck.width
let height = RectCheck.height
// チェックマークの描画 ----------------------
let checkmark = UIBezierPath()
//起点
checkmark.moveToPoint(CGPointMake(xx + width / 6, yy + height / 2))
//帰着点
checkmark.addLineToPoint(CGPointMake(xx + width / 3, yy + height * 7 / 10))
checkmark.addLineToPoint(CGPointMake(xx + width * 5 / 6, yy + height * 1 / 3))
// 色の設定
checkColor.setStroke()
// ライン幅
checkmark.lineWidth = 6
// 描画
checkmark.stroke()
}
}
丸い形のチェックボックスになります. このクラスのselectedがfalseなら薄い灰色,trueなら緑になるようにしています.
CustomCollectionViewCell
import UIKit
class CustomCollectionViewCell: UICollectionViewCell {
var testView : UIView?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
override init(frame: CGRect) {
super.init(frame: frame)
testView = UIView()
testView!.backgroundColor = UIColor.brownColor()
self.backgroundView = testView
let boxSize = frame.width * 0.3
let falseBox = CheckBoxView(frame: CGRectMake(0, 0, boxSize, boxSize), selected: false)
self.addSubview(falseBox)
let trueBox = CheckBoxView(frame: CGRectMake(0, 0, boxSize, boxSize), selected: true)
let backView = UIView(frame: frame)
backView.backgroundColor = UIColor.clearColor()
backView.addSubview(trueBox)
self.selectedBackgroundView = backView
}
}
Cellに標準でfalseなCheckBoxを置いておきます. そしてCellのselectedBackgroundViewというプロパティにtrueなCheckBoxを入れます.
selectedBackgroundView
selectedBackgroundViewはCellが選択状態にある時にCellに表示されるViewです.デフォルトではnilですがここにViewを入れておくとそのViewが表示されます.
しかしここで問題なのですがCellのcontentViewになにかViewが入っているとこのselectedBackgroundViewが選択状態でも表示されないようです.
CellのbackgroundViewになにかCellに表示したいViewを設定するのが重要です.
最初contentViewにセットしていたのですが上にあるようにこれだとうまくいきません.
CollectionViewController
import UIKit
class CollectionViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource{
var myCollectionView:UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let width = self.view.bounds.width
let cellSize = width * 0.5 - 12
// CollectionViewのレイアウトを生成.
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSizeMake(cellSize, cellSize)
layout.sectionInset = UIEdgeInsetsMake(16, 8, 32, 8)
print(layout.minimumLineSpacing)
layout.minimumLineSpacing = 10 //cellの縦のマージン
layout.minimumInteritemSpacing = 8 //cellの横のマージン
layout.headerReferenceSize = CGSizeMake(100,30)
// CollectionViewを生成.
myCollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
myCollectionView.registerClass(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
myCollectionView.delegate = self
myCollectionView.dataSource = self
myCollectionView.backgroundColor = UIColor.whiteColor()
myCollectionView.allowsMultipleSelection = true
self.view.addSubview(myCollectionView)
}
//MARK:- UICollectionViewDataSorce
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! CustomCollectionViewCell
//ここでcell.testViewなどcellのbackgroundViewにあるViewになにか必要な要素を配置する
return cell
}
//MARK:UICollectionViewDelegate
//選択された時に呼ばれる.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! CustomCollectionViewCell
print(cell.selected)
//選択された時に選択されているCellのindexPathを表示
let selecteditems = self.myCollectionView.indexPathsForSelectedItems()
print(selecteditems)
}
//選択状態から非選択状態になった時に呼ばれる.
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCell", forIndexPath: indexPath) as! CustomCollectionViewCell
print(cell.selected)
}
}
allowsMultipleSelection
myCollectionView.allowsMultipleSelection = true の一行をしっかり入れましょう.
これはCellの複数選択を許可するcollectionViewのプロパティです.
これをtrueにすることでCellの複数選択が可能になります.
デフォルトではこれはfalseなので一つしか選択できない状態になります.
それ以外は普通にCollectionViewを設定してそこにCustomCellを登録して使いましょう.
選択されたCellを取得するには
self.myCollectionView.indexPathsForSelectedItems()
というメソッドを使いましょう.これで選択されているCellのindexPathを配列の形で取得することができます.
今回作ったサンプルをGithubにあげておきます.