はじめに
グリッド形式とリスト形式を切り替える画面は、たまに見ますよね。
今回は、CollectionViewを利用したサンプルをご紹介します。
完成イメージ
実装手順
- グリッド形式のレイアウトを作成する
- リスト形式のレイアウトを作成する
- カスタムCollectionViewCellを作成する
- レイアウトを作成する
- セグメントコントロールで表示形式を切り替える
実装してみます
1. グリッド形式のレイアウトを作成する
2列毎にレイアウトします。
GridFlowLayout.swift
import UIKit
class GridFlowLayout: UICollectionViewFlowLayout {
let itemHeight: CGFloat = 160
override var itemSize: CGSize {
set {
self.itemSize = CGSizeMake(itemWidth(), itemHeight)
}
get {
return CGSizeMake(itemWidth(), itemHeight)
}
}
override init() {
super.init()
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLayout()
}
func setupLayout() {
minimumInteritemSpacing = 1
minimumLineSpacing = 1
scrollDirection = .Vertical
}
func itemWidth() -> CGFloat {
return (CGRectGetWidth(collectionView!.frame)/2)-1
}
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint {
return collectionView!.contentOffset
}
}
2. リスト形式のレイアウトを作成する
グリッド形式のレイアウトとほぼ同じコードで冗長ですが、
1列毎にレイアウトします。
ListFlowLayout.swift
import UIKit
class ListFlowLayout: UICollectionViewFlowLayout {
var itemHeight: CGFloat = 160
override var itemSize: CGSize {
set {
self.itemSize = CGSizeMake(itemWidth(), itemHeight)
}
get {
return CGSizeMake(itemWidth(), itemHeight)
}
}
override init() {
super.init()
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLayout()
}
func setupLayout() {
minimumInteritemSpacing = 0
minimumLineSpacing = 1
scrollDirection = .Vertical
}
func itemWidth() -> CGFloat {
return CGRectGetWidth(collectionView!.frame)
}
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint {
return collectionView!.contentOffset
}
}
3. カスタムCollectionViewCellを作成する
ImageViewがあるだけのセルを作ります。
import UIKit
class ImageCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var imageView: UIImageView!
static var identifier: String {
get {
return String(self)
}
}
}
4. レイアウトを作成する
SegmentedControlとCollectionViewを配置します。
なお、SegmentedControlは、
グリッド形式とリスト形式を切り替えるために利用します。
また、CollectionViewのみを利用し、TableViewは利用しません。

5. セグメントコントロールで表示形式を切り替える
5.1. Viewのタイプを定義する
グリッド形式とリスト形式の2パターンを定義します。
ViewController.swift
enum ViewType {
case grid
case list
}
5.2. セグメントコントロールのイベントを受けて、レイアウトを切り替える
CollectionViewのsetCollectionViewLayoutメソッドを利用して、
所定のレイアウト(grid or list)に変更します。
アニメーションをつけると、それっぽくなります。
class ViewController: UIViewController {
@IBOutlet weak var typeSegmentControl: UISegmentedControl!
@IBOutlet weak var collectionView: UICollectionView!
let gridFlowLayout = GridFlowLayout()
let listFlowLayout = ListFlowLayout()
var fileNames = [String]()
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
private func setup() {
//テストデータ
for i in 1...10 {
fileNames.append("\(i)")
}
collectionView.collectionViewLayout = gridFlowLayout
}
//セグメントコントロールで表示形式を切り替えます
@IBAction func onDidTappedType(sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case ViewType.grid.hashValue:
changeView(gridFlowLayout)
break
case ViewType.list.hashValue:
changeView(listFlowLayout)
break
default:
break
}
}
//Viewを切り替えます
private func changeView(flowLayout: UICollectionViewFlowLayout) {
UIView.animateWithDuration(0.2) { [weak self] () -> Void in
self?.collectionView.collectionViewLayout.invalidateLayout()
self?.collectionView.setCollectionViewLayout(flowLayout, animated: true)
}
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return fileNames.count
}
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(ImageCollectionViewCell.identifier,
forIndexPath: indexPath) as! ImageCollectionViewCell
cell.imageView.image = UIImage(named: "\(fileNames[indexPath.row])"+".jpg")
return cell
}
}
まとめ
グリッド形式とリスト形式を切り替えるには、
TableViewとCollectionViewを併用する方法もありますが、
シンプルなレイアウトなら、CollectionViewの列数を調整しても良さそうです。
参考