CollectionViewに区切り線を追加する
CollectionViewに区切り線を追加する方法です。

参考:
UICollectionView の Layout で悩んだら
Decoration Viewを用いてCollection Viewに区切り線と背景を追加する
CollectionViewFlowLayoutWithDecorations.swift
import UIKit
class CollectionViewFlowLayoutWithDecorations: UICollectionViewFlowLayout {
enum DecorationViewElementKind: String {
case verticalSeparator
static var separators: [DecorationViewElementKind] {
return [ .verticalSeparator]
}
}
let separatorSize: CGSize = CGSize(width: 2, height: 2)
override init() {
super.init()
register(SeparatorView.self, forDecorationViewOfKind: DecorationViewElementKind.verticalSeparator.rawValue)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let layoutAttributesArray = super.layoutAttributesForElements(in: rect) else {
return nil
}
var decorationLayoutAttributesArray: [UICollectionViewLayoutAttributes] = []
for layoutAttributes in layoutAttributesArray {
let indexPath = layoutAttributes.indexPath
decorationLayoutAttributesArray += DecorationViewElementKind.separators.compactMap {
return layoutAttributesForDecorationView(ofKind: $0.rawValue, at: indexPath)
}
}
return layoutAttributesArray + decorationLayoutAttributesArray
}
override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let decorationViewElementKind = DecorationViewElementKind(rawValue: elementKind) else {
return super.layoutAttributesForDecorationView(ofKind: elementKind, at: indexPath)
}
switch decorationViewElementKind {
case .verticalSeparator:
guard
indexPath.row > 0,
separatorSize.width > 0,
let itemLayoutAttributes = layoutAttributesForItem(at: indexPath)
else {
return nil
}
let layoutAttributes = UICollectionViewLayoutAttributes(forDecorationViewOfKind: elementKind, with: indexPath)
layoutAttributes.frame = CGRect(
x: itemLayoutAttributes.frame.origin.x - ((minimumInteritemSpacing + separatorSize.width) / 2).rounded(.down),
y: itemLayoutAttributes.frame.origin.y,
width: separatorSize.width,
height: itemLayoutAttributes.frame.size.height
)
return layoutAttributes
}
}
}
SeparatorView.swift
import UIKit
class SeparatorView: UICollectionReusableView {
let path = UIBezierPath()
let shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
self.frame = layoutAttributes.frame
}
override func layoutSubviews() {
super.layoutSubviews()
path.move(to: CGPoint(x: frame.size.width / 2, y: 4))
path.addLine(to: CGPoint(x: frame.size.width / 2, y: frame.size.height - 4))
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.lightGray.cgColor
shapeLayer.lineWidth = 2
shapeLayer.lineCap = CAShapeLayerLineCap.round
layer.addSublayer(shapeLayer)
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
var collectionView : UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// CollectionViewのレイアウトを生成.
let layout = CollectionViewFlowLayoutWithDecorations()
layout.scrollDirection = .horizontal
// Cell一つ一つの大きさ.
layout.itemSize = CGSize(width: 52, height: 52)
// セルのマージン.
layout.sectionInset = UIEdgeInsets.zero
// セルの横方向のマージン
layout.minimumInteritemSpacing = 10
// セルの縦方向のマージン
layout.minimumLineSpacing = 10
// セクション毎のヘッダーサイズ.
layout.headerReferenceSize = CGSize(width: 0, height: 0)
// CollectionViewを生成.
let collectionFrame = CGRect(x: 0, y: view.bounds.height / 2, width: view.bounds.width, height: 52)
collectionView = UICollectionView(frame: collectionFrame, collectionViewLayout: layout)
// Cellに使われるクラスを登録.
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(UICollectionViewCell.self))
// Indicater を隠す
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = UIColor.clear
view.addSubview(collectionView)
view.backgroundColor = .white
}
}
extension ViewController: UICollectionViewDataSource {
// Cellの総数を返す
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 25
}
// Cellに値を設定する
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(UICollectionViewCell.self), for: indexPath as IndexPath)
cell.backgroundView = UIImageView(image: UIImage(named: "icon")!)
return cell
}
}
extension ViewController: UICollectionViewDelegate {
// Cellが選択された際に呼び出される
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Num: \(indexPath.row)")
}
}
