こんばんは!
セプテーニ・オリジナルの寺坂です。
現在、エンジニア一年目。
勉強の日々でございます。
いまの仕事で「iOS開発」に携わっているので、
今回は、Swiftネタを書きます。
つたない所があるかもしれませんが、
温かい目で最後までご一読いただけると嬉しいです!
それでは、よろしくお願いします。
スワイプ移動ページUIの実現
ここでの スワイプ移動ページUI とは、
「あらかじめ複数のページを横に並べておいて、
スワイプによって横スクロール式にページを切り替える」
UIを指しています。
たとえば、
トップにナビゲーションバーやセグメントを固定しておいて、
その下のページをスワイプで切り替えたい時
などを想定してます。
横スクロール型UIと言ってもいいかもしれませんね。
CollectionViewなら実装コードが少なくなる
このスワイプ移動ページUIを実現する方法はいくつかありますが、
PageViewとかScrollViewを使うと、実装の手間がかかりがちです。
そこで、今回はより簡単な方法を模索して、
UICollectionViewを使ったスワイプ移動ページUI
を実現したいと思います。
1. UICollectionViewControllerを継承させる
まず始めに、Storyboard上にUICollectionViewControllerを追加して、
コントローラーとひもづけましょう。
UICollectionView自体の解説は本筋から外れるので、
詳細は割愛してざっくり説明で進みます。
手順
- StoryboardにCollectionViewを追加
- Layoutは「Flow」
- Scroll Directionは「Horizontal」
- Scrollingの「Paging Enabled」にチェック
- UICollectionViewControllerを継承したPageCollectionViewControllerを作成
- StoryboardのUICollectionViewControllerのコントローラーにPageCollectionViewControllerを指定
実装
import UIKit class PageCollectionViewController: UICollectionViewController { var pages:Pages = Pages(){ didSet { self.collectionView?.reloadData() } } override func viewDidLoad() { super.viewDidLoad() } }
2. データの準備とUICollectionViewDelegateの実装
最低限、セルの数とセルの種類を返すdelegateは実装しましょう。
手順
- 構造体を定義
- 組み込みたいページを追加
- "PageCollectionViewCell"というIDでUICollectionViewCellを用意
- 構造体に定義されている数だけ、CollectionViewCellを作る
実装
import UIKit struct Pages { var viewControllers:[UIViewController] = [] } class PageCollectionViewController: UICollectionViewController { var pages:Pages = Pages(){ didSet { self.collectionView?.reloadData() } } override func viewDidLoad() { super.viewDidLoad() let page1 = UIViewController() page1.view.backgroundColor = UIColor.yellowColor() self.pages.viewControllers.append(page1) let page2 = UIViewController() page2.view.backgroundColor = UIColor.blueColor() self.pages.viewControllers.append(page2) } // MARK: - UICollectionViewDelegate override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.pages.viewControllers.count } override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { var cell = collectionView.dequeueReusableCellWithReuseIdentifier("PageCollectionViewCell", forIndexPath: indexPath) as UICollectionViewCell let view = self.pages.viewControllers[indexPath.row].view return cell } }
3. セルにページをaddSubviewする
次の部分を編集して、
indexPathに対応するviewをセルに貼付けましょう。
手順
- indexPathに対応するviewを取り出す
- cell.contentViewにはり付ける
実装
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { var cell = collectionView.dequeueReusableCellWithReuseIdentifier("PageCollectionViewCell", forIndexPath: indexPath) as UICollectionViewCell let view = self.pages.viewControllers[indexPath.row].view cell.contentView.addSubview(view) return cell } }
4.セルのサイズを動的に変える
ここまでの実装で、セルにページ情報を表示させることが出来ますが、
セルのサイズが小さいままです。
次は、セルサイズを画面全体の大きさに変動させましょう。
そのためには、作成したPageCollectionViewControllerに
UICollectionViewDelegateFlowLayoutのメソッドを実装します。
ここでは次のようにコードを追加します。
1つ目のメソッドで返すCGSizeがセルの大きさになり、
残りの2つは、それぞれ横のスペース・縦のスペースになります。
(後の2つはStoryboardからも設定可)
注意点
- 状況によってはAutoLayoutとの兼ね合いに注意が必要です
手順
- メソッド内で実現したいCGSizeを求めて返す
- セルとセルの間スペースは、0を指定
実装
/// セルの大きさ func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { var pageViewRect = self.view.bounds return CGSize(width: pageViewRect.width, height: pageViewRect.height) } /// 横のスペース func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat { return 0.0 } /// 縦のスペース func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat { return 0.0 }
完成
以上です。
最後に完成したコードを載せておきます。
コードを整理してコンパクトにすると、ぴったり50行。
最後まで読んでくださり
ありがとうございました!
元記事は、こちらです。
[swift]スワイプ移動できるページUIを50行で実装する
実装
import UIKit struct Pages { var viewControllers:[UIViewController] = [] } class PageCollectionViewController: UICollectionViewController { var pages:Pages = Pages(){ didSet { self.collectionView?.reloadData() } } override func viewDidLoad() { super.viewDidLoad() self.collectionView?.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "PageCollectionViewCell") let page1 = UIViewController() page1.view.backgroundColor = UIColor.yellowColor() self.pages.viewControllers.append(page1) let page2 = UIViewController() self.pages.viewControllers.append(page2) } // MARK: - UICollectionViewDelegate override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.pages.viewControllers.count } override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { var cell = collectionView.dequeueReusableCellWithReuseIdentifier("PageCollectionViewCell", forIndexPath: indexPath) as UICollectionViewCell let view = self.pages.viewControllers[indexPath.row].view cell.contentView.addSubview(view) return cell } func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { var pageViewRect = self.view.bounds return CGSize(width: pageViewRect.width, height: pageViewRect.height) } func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat { return 0.0 } func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat { return 0.0 } }