Skip to content

Instantly share code, notes, and snippets.

@hahnah
Created August 1, 2018 11:42
Show Gist options
  • Save hahnah/ce942b0f01ce75eea2f86986d6cd4759 to your computer and use it in GitHub Desktop.
Save hahnah/ce942b0f01ce75eea2f86986d6cd4759 to your computer and use it in GitHub Desktop.
Fixed Sample code showing checkmark on UICollectionViewCell. This is fixed version of https://gist.github.com/hahnah/2b3f0f373562e1cdc80740b7e0ff5d47
import UIKit
class CollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var collectionView : UICollectionView!
var toolbar: UIToolbar?
override func viewDidLoad() {
super.viewDidLoad()
let viewWidth = self.view.frame.width
let viewHeight = self.view.frame.height
let collectionFrame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)
// CollectionViewのレイアウトを生成.
let layout = UICollectionViewFlowLayout()
// Cell間の最小サイズ
layout.minimumInteritemSpacing = 4
// 行間の最小サイズ
layout.minimumLineSpacing = 4
// Cellのマージン.
layout.sectionInset = UIEdgeInsets.zero
//layout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16)
// セクションのヘッダーサイズ
layout.headerReferenceSize = CGSize(width:0,height:0)
// Cellサイズを適当に決める
layout.itemSize = CGSize(width: (viewWidth - layout.minimumInteritemSpacing - 8) / 3, height: (viewWidth - layout.minimumLineSpacing - 8) / 3)
// CollectionViewを生成.
collectionView = UICollectionView(frame: collectionFrame, collectionViewLayout: layout)
// Cell に使われるクラスとして CustomCell を登録
collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "MyCell")
collectionView.delegate = self
collectionView.dataSource = self
self.view.addSubview(collectionView)
// 複数選択を許可
self.collectionView.allowsMultipleSelection = true
}
// Cell の総数
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 36
}
// Cell に値を設定する
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CustomCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CustomCell
cell.contentView.backgroundColor = UIColor.yellow
// 古い subview を削除
cell.contentView.subviews.forEach { subview in
subview.removeFromSuperview()
}
// checkmarkをつけ直す
if CustomCell.hasCellAppearedInThePast(selectedItemAt: indexPath) {
if CustomCell.shouldCellBeMarked(selectedItemAt: indexPath) {
cell.mark(selectedItemAt: indexPath)
} else {
cell.unmark(deselectedItemAt: indexPath)
}
}
return cell
}
// Cell がタップで選択されたときに呼ばれる
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell: CustomCell = collectionView.cellForItem(at: indexPath) as? CustomCell else { return }
if self.collectionView.allowsMultipleSelection {
cell.mark(selectedItemAt: indexPath)
}
}
// Cell がタップで選択解除されたときに呼ばれる
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell: CustomCell = collectionView.cellForItem(at: indexPath) as? CustomCell else { return }
if self.collectionView.allowsMultipleSelection {
cell.unmark(deselectedItemAt: indexPath)
}
}
}
import UIKit
class CustomCell: UICollectionViewCell {
let checkmarkImage: UIImage = UIImage(named: "checkmark")!
var checkmarkView: UIImageView!
static var allCells: [CustomCell] = []
// 全 Cell のチェックマークの有無を記憶
static var checkmarkStates: [Bool] = []
// 全チェックマークを消す
static func clearAllCheckmarks() -> Void {
allCells.filter { cell in cell.isMarked } .forEach { cell in
cell.isMarked = false
}
checkmarkStates = checkmarkStates.map { _ in
return false
}
}
// indexPath.row 番目の Cell が既に作成されているかどうか判定
static func hasCellAppearedInThePast(selectedItemAt indexPath: IndexPath) -> Bool {
if indexPath.row + 1 <= checkmarkStates.count {
return true
} else {
return false
}
}
// indexPath.row 番目の Cell にチェックマークがついているか判定
static func shouldCellBeMarked(selectedItemAt indexPath: IndexPath) -> Bool {
if checkmarkStates[indexPath.row] {
return true
} else {
return false
}
}
// チェックマーク有無
private var isMarked: Bool = false {
didSet {
if isMarked {
self.contentView.addSubview(self.checkmarkView!)
} else {
self.checkmarkView?.removeFromSuperview()
}
}
}
// チェックマークをつける
func mark(selectedItemAt indexPath: IndexPath) -> Void {
self.isMarked = true
CustomCell.checkmarkStates[indexPath.row] = true
}
// チェックマークを消す
func unmark(deselectedItemAt indexPath: IndexPath) -> Void {
self.isMarked = false
CustomCell.checkmarkStates[indexPath.row] = false
}
override init(frame: CGRect) {
super.init(frame: frame)
self.checkmarkView = UIImageView(image: self.checkmarkImage)
CustomCell.checkmarkStates.append(false)
CustomCell.allCells.append(self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import UIKit
class ExtendedCollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var collectionView : UICollectionView!
var toolbar: UIToolbar?
override func viewDidLoad() {
super.viewDidLoad()
let viewWidth = self.view.frame.width
let viewHeight = self.view.frame.height
let collectionFrame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)
// CollectionViewのレイアウトを生成.
let layout = UICollectionViewFlowLayout()
// Cell間の最小サイズ
layout.minimumInteritemSpacing = 4
// 行間の最小サイズ
layout.minimumLineSpacing = 4
// Cellのマージン.
layout.sectionInset = UIEdgeInsets.zero
//layout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16)
// セクションのヘッダーサイズ
layout.headerReferenceSize = CGSize(width:0,height:0)
// Cellサイズを適当に決める
layout.itemSize = CGSize(width: (viewWidth - layout.minimumInteritemSpacing - 8) / 3, height: (viewWidth - layout.minimumLineSpacing - 8) / 3)
// CollectionViewを生成.
collectionView = UICollectionView(frame: collectionFrame, collectionViewLayout: layout)
// Cell に使われるクラスとして CustomCell を登録
collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "MyCell")
collectionView.delegate = self
collectionView.dataSource = self
self.view.addSubview(collectionView)
// Toolbarを生成
let toolbarHeight: CGFloat = 60
let toolbarPaddingBottom: CGFloat = 20
let toolbarRect: CGRect = CGRect(x: 0, y: self.view.bounds.height - toolbarHeight - toolbarPaddingBottom, width: self.view.bounds.width, height: toolbarHeight)
toolbar = UIToolbar(frame: toolbarRect)
toolbar?.items = self.generateToolbarButtons(isMultipleSelectionMode: self.collectionView.allowsMultipleSelection, isAnyCellselected: false)
self.view.addSubview(toolbar!)
}
// Cell の総数
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 36
}
// Cell に値を設定する
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CustomCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CustomCell
cell.contentView.backgroundColor = UIColor.yellow
// 古い subview を削除
cell.contentView.subviews.forEach { subview in
subview.removeFromSuperview()
}
// checkmarkをつけ直す
if CustomCell.hasCellAppearedInThePast(selectedItemAt: indexPath) {
if CustomCell.shouldCellBeMarked(selectedItemAt: indexPath) {
cell.mark(selectedItemAt: indexPath)
} else {
cell.unmark(deselectedItemAt: indexPath)
}
}
return cell
}
// Cell がタップで選択されたときに呼ばれる
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell: CustomCell = collectionView.cellForItem(at: indexPath) as? CustomCell else { return }
if self.collectionView.allowsMultipleSelection {
cell.mark(selectedItemAt: indexPath)
}
let numberOfSelectedItems: Int? = collectionView.indexPathsForSelectedItems?.count
if numberOfSelectedItems == 1 {
let toolbarButtons: [UIBarButtonItem] = self.generateToolbarButtons(isMultipleSelectionMode: self.collectionView.allowsMultipleSelection, isAnyCellselected: true)
self.toolbar?.setItems(toolbarButtons, animated: true)
}
}
// Cell がタップで選択解除されたときに呼ばれる
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell: CustomCell = collectionView.cellForItem(at: indexPath) as? CustomCell else { return }
if self.collectionView.allowsMultipleSelection {
cell.unmark(deselectedItemAt: indexPath)
}
let numberOfSelectedItems: Int? = collectionView.indexPathsForSelectedItems?.count
if numberOfSelectedItems == 0 {
let toolbarButtons: [UIBarButtonItem] = self.generateToolbarButtons(isMultipleSelectionMode: self.collectionView.allowsMultipleSelection, isAnyCellselected: false)
self.toolbar?.setItems(toolbarButtons, animated: true)
}
}
// Select ボタンが押されたときに呼び出される
@objc func enableSelect(_ sender: UIBarButtonItem) -> Void {
self.collectionView.allowsSelection = false
self.collectionView.allowsMultipleSelection = true
self.toolbar?.setItems(self.generateToolbarButtons(isMultipleSelectionMode: self.collectionView.allowsMultipleSelection, isAnyCellselected: false), animated: true)
}
// Cancel ボタンが押されたときに呼び出される
@objc func disableSelect(_ sender: UIBarButtonItem) -> Void {
let indexPaths = self.collectionView.indexPathsForSelectedItems!
indexPaths.forEach { indexPath in
self.collectionView.deselectItem(at: indexPath, animated: false)
}
CustomCell.clearAllCheckmarks()
self.collectionView.allowsSelection = true
self.collectionView.allowsMultipleSelection = false
self.toolbar?.setItems(self.generateToolbarButtons(isMultipleSelectionMode: self.collectionView.allowsMultipleSelection, isAnyCellselected: false), animated: true)
}
// Toolbar のボタンを生成
func generateToolbarButtons(isMultipleSelectionMode: Bool, isAnyCellselected: Bool) -> [UIBarButtonItem] {
var buttons: [UIBarButtonItem] = []
let addButton: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: nil)
let cameraButton: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .camera, target: self, action: nil)
let sendButton: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: nil)
let trashButton: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .trash, target: self, action: nil)
let selectButton: UIBarButtonItem = UIBarButtonItem(title: "Select", style: .plain, target: self, action: #selector(self.enableSelect(_:)))
let cancelButton: UIBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(self.disableSelect(_:)))
let buttonGap: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let selectOrCancelButton: UIBarButtonItem
if isMultipleSelectionMode {
addButton.isEnabled = false
cameraButton.isEnabled = false
sendButton.isEnabled = false
trashButton.isEnabled = isAnyCellselected ? true : false
cancelButton.isEnabled = true
selectOrCancelButton = cancelButton
} else {
trashButton.isEnabled = false
selectOrCancelButton = selectButton
}
buttons = [addButton, buttonGap, cameraButton, buttonGap, sendButton, buttonGap, trashButton, buttonGap, selectOrCancelButton]
return buttons
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment