【Swift】CollectionViewでカード型デザインを実装しよう

今回はCollectionViewを使って横スクロールできるカード型デザインを実装しました!


完成品

cardDesignSample.gif


1. Storyboardの編集

まずはStoryboardでViewController上にCollectionViewを配置します。画面いっぱいにパーツを広げ、Constrainsを適切に設定しておきます。

スクリーンショット 2019-06-11 11.05.08.png

デフォルトでCollectionViewのスクロール方向はVerticalになっているのでScroll DirectionHorizontalに変更しておきましょう。

スクリーンショット 2019-06-11 11.55.23.png


2. CollectionViewのカスタムセルを作成

次にカスタムセルのxibファイルを作成します。

XCodeメニューのFile > New > File...とたどり、Cocoa Touch Classを選択します。

スクリーンショット 2019-06-11 11.12.45.png

クラスの型はUICollectionViewCellにして、名前をつけます(ここではCollectionViewCellという名前をつけています)。この際にAlso create XIB fileにチェックをつけるのを忘れないように注意してください。

スクリーンショット 2019-06-11 11.13.00.png

CollectionViewCell.xibファイルができたらパーツを適宜配置します。今回は背景のUIImageViewを画面いっぱいに広げ、その上にUILabelを2つ配置しました。

スクリーンショット 2019-06-11 11.17.24.png

UIImageViewのContentModeは以下のように'AspectFillとし、Clip to Bounds`にチェックを入れるのを忘れないように注意してください。

スクリーンショット 2019-06-11 11.50.43.png

cellにはidentifierをつけておきます。ここではcellとしておきます。

スクリーンショット 2019-06-11 11.22.26.png

CollectionView.swiftでは配置したパーツの宣言を行い、背景の角を丸くしておきます。関連付けも忘れないようにしておきましょう。

import UIKit

class CollectionViewCell: UICollectionViewCell {

@IBOutlet var titleLabel: UILabel!
@IBOutlet var dateLabel: UILabel!
@IBOutlet var backgroundImageView: UIImageView!

override func awakeFromNib() {
super.awakeFromNib()

backgroundImageView.layer.cornerRadius = 12
}
}


3. ViewControllerの編集

初めにViewDidLoad()内でregister(_:forCellWithReuseIdentifier:)メソッドを使ってCollectionViewCellの登録を行います。第一引数にUINibオブジェクトを渡し、第二引数では先ほどcellにつけたcellというidentifierを渡しています。UINibのnibNameはCollectionViewのxibファイル名と一致していることを確認してください。

import UIKit

class ViewController: UIViewController {

@IBOutlet var horizontalCollectionView: UICollectionView!

override func viewDidLoad() {
super.viewDidLoad()

let nib = UINib(nibName: "CollectionViewCell", bundle: .main)
horizontalCollectionView.register(nib, forCellWithReuseIdentifier: "cell")
}
}

次にViewControllerにUICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayoutプロトコルを実装します。今回は以下の4つのメソッドを実装しました。

コレクションビューに配置するセルの個数

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {}1番目のメソッドではphotoArrayの中に入っている写真の個数だけセルを返し、3番目のメソッドでセルを再利用しているところがポイントです。


  1. セルの中身

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {}


  2. セル同士の間隔

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {}


  3. セルのサイズ

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {}


  4. 余白の調整

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {}


全体のコードは以下の通りです。

ViewController.swift

import UIKit

class ViewController: UIViewController {

@IBOutlet var horizontalCollectionView: UICollectionView!

var viewWidth: CGFloat!
var viewHeight: CGFloat!
var cellWidth: CGFloat!
var cellHeight: CGFloat!
var cellOffset: CGFloat!
var navHeight: CGFloat!

var photoArray = ["ny","italy","australia","france"]
var titleArray = ["ニューヨーク","イタリア","オーストラリア","フランス"]

override func viewDidLoad() {
super.viewDidLoad()

viewWidth = view.frame.width
viewHeight = view.frame.height
navHeight = self.navigationController?.navigationBar.frame.size.height

horizontalCollectionView.delegate = self
horizontalCollectionView.dataSource = self

let nib = UINib(nibName: "CollectionViewCell", bundle: .main)
horizontalCollectionView.register(nib, forCellWithReuseIdentifier: "cell")

self.navigationController!.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController!.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.titleTextAttributes = [
.foregroundColor: UIColor.white
]

}

}

extension ViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photoArray.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.backgroundColor = UIColor.white
cell.layer.cornerRadius = 12
cell.layer.shadowOpacity = 0.4
cell.layer.shadowRadius = 12
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 8, height: 8)
cell.layer.masksToBounds = false
cell.titleLabel.text = "\(titleArray[indexPath.row])への旅"
cell.dateLabel.text = "06/08~06/15"
cell.backgroundImageView.image = UIImage(named: photoArray[indexPath.row])
return cell

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 24
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
cellWidth = viewWidth-75
cellHeight = viewHeight-300
cellOffset = viewWidth-cellWidth
return CGSize(width: cellWidth, height: cellHeight)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: -navHeight,left: cellOffset/2,bottom: 0,right: cellOffset/2)
}

}

CollectionView.swift

import UIKit

class CollectionViewCell: UICollectionViewCell {

@IBOutlet var titleLabel: UILabel!
@IBOutlet var dateLabel: UILabel!
@IBOutlet var backgroundImageView: UIImageView!

override func awakeFromNib() {
super.awakeFromNib()

backgroundImageView.layer.cornerRadius = 12
}
}