18
UIPageViewControllerとContainerViewで こんな見た目を実現するTips 集まれSwift好き!Swift愛好会 #6 2016/04/24 Fumiya Sakai

UIPageViewControllerとContainerViewでこんな見た目を実現するTips

Embed Size (px)

Citation preview

Page 1: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

UIPageViewControllerとContainerViewで

こんな見た目を実現するTips

集まれSwift好き!Swift愛好会#6

2016/04/24FumiyaSakai

Page 2: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

自己紹介と簡単な経歴など

✦ 今までの仕事履歴(本業)

石川県金沢市生まれ

本業はサーバーサイドのプログラマ※Rails&PHP使い

26歳〜31歳: Webプログラマ(PHP&Rubyがキャリア長い)

23歳〜25歳: Webデザイナー兼ディレクター

チャンスがあればiOSアプリ開発も絶賛やってみたい!

趣味:シルバーアクセサリー集め・スイーツ作り・アプリ開発

女子向け・グルメ・エンタメ関連のお仕事が多い

Qiita:http://qiita.com/fumiyasac@github

Github:https://github.com/fumiyasac

✦ 酒井文也(さかいふみや)

東京(大塚)住まいの31歳

こんな格好を普段からしているので遊び人に見られますがエンジニアです。

文系卒に思われますが実は数学科で理系卒です。

めっちゃお酒好きそうに見えますがビール苦手でお酒も超弱いです。

今でもたまにUIまわりとか触りたくなることがあったりなかったり

今年の4月からフリーランスです。(今は渋谷のとある会社にいます)

最近のはまっている食べ物はカボチャと担々麺です。

最近はSwift以外ではRailsやLaravel・CakePHP・Node.jsなんかも

Page 3: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

これまでに作ったもの(ネイティブアプリ)

①簡易家計簿アプリ「Coffre」

②ゲームアプリ「10秒虫食い算」

・カレンダーを自作しています

・シンプルなお小遣い帳感覚で支出管理できます

・全問正解者ほとんどいません…

・不定期ですがコラムも書いています

・サーバーサイドはRubyonRailsを使用

http://www.coffre.me/

・デザインにもこだわってみました(特にグラフ)

・実はちょっとバグがあります。

・問題は今後追加予定(現在110問収録)

個人的にはなりますが、他にもアプリ・Webサービスなど開発中です(2016年も宜しくお願いします)

・サイト等は次回のアップデートで公開予定

http://blog.just1factory.net/services/284

・若干の中毒性を含みます

Page 4: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ ViewControllerをひとまとめにして扱ってくれる優れもの

UIPageViewControllerについての基礎知識

・アプリの最初のチュートリアル画面もよく用いられる表現方法

・ニュースメディアアプリやキュレーションアプリのタブと連動させて中を変えるUIにも使われる

親のViewControllerが子のViewController達を管理してくれるので、ViewControllerの責務を明確にできる

★それぞれの子のViewControllerの独立性を維持しながら切り替えることが可能

Page 5: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ ContainerViewを活用するとUIを作る幅が広がる場面も

ContainerViewについての基礎知識

多用禁物だけどViewControllerを重ねる場合や親のViewControllerの一部に別の部品を表示する場合に便利

★組み合わせ方でUIPageViewControllerみたいなものや重なりを表現することも可能

・UIScrollView+ContainerViewを使用してUIPageViewControllerのような動きももちろん可能

・隠れているメニューをメイン側のボタンから操作して表示させるようなUIの表現もできる

Page 6: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ PageViewControllerとContainerViewのサンプル2種類

今回のサンプルの概要

PageViewControllerはコードでレイアウト・ContainerViewのものはAutoLayoutとコード配置の合わせ技で

★どちらも似たような動きをしているものですが、実装の違いを見極めてみよう

・ViewController同士の重なりを考慮する場合はContainerViewを使うときれいにまとめられる

ハンバーガーボタンを押すと下に隠れているメニューの部分が表示

ページをめくるようなここは、(.PageCurl)で実現※デフォルト

UIScrollView+Containerでスクロールでコンテンツ切り替え

上のタブコンテンツに連動して動くラベルとコンテンツが連動

UIPageViewControllerでコンテンツ切り替え

・UIPageViewControllerはViewControllerの管理と切り替え

Page 7: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ 今回もサンプルと詳細な解説をご用意しました

サンプルはこちら

間違いやご指摘・もしくはもっとエレガントな実装のアイデアやご提案がありましたら是非ぜひお気軽に!

★サンプルはこちら

・組み方の手法やTipsに関しては色々手法があるので一つの解として捉えて頂ければ幸いです。

・UI系のライブラリに近しい動きをできるだけ強引に再現してみた形になります。

・Github:https://github.com/fumiyasac/CustomizeUISample

★詳細な解説はこちら

iPhoneアプリでUIを作るためのTipsとContainerView・UIPageViewControllerを使ったサンプル紹介

・Qiita:http://qiita.com/fumiyasac@github/items/1244abc8e3286c47ef50

★(参考)AutoLayoutを用いないで実装した例

メディア系アプリでよくあるUIを実現した簡易サンプル

・Qiita:http://qiita.com/fumiyasac@github/items/2490990be4c011935368

・Github:https://github.com/fumiyasac/mediaStyleContainer

Page 8: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ Storyboardに作成したViewControllerをひとまとめにする

PageViewControllerを使用したサンプル解説

PageViewControllerに入れるViewControllerを管理する際にはViewControllerのリストを追加する必要あり

★PageViewControllerで管理するViewControllerの一覧を取得する

・今回はUIPageViewControllerクラスを使う部分についてはコードで配置する方針

・各ViewControllerの”Identifier”をもとに追加対象のViewController達のリストを作成

//UIPageViewControllerに配置するUIViewControllerクラスの名称 static let pageControllerIdentifierList : [String] = [ "FirstViewController", "SecondViewController", "ThirdViewController", "FourthViewController", "FifthViewController", "SixthViewController" ] //UIPageViewControllerに追加するViewControllerのリストを生成する static func generateViewControllerList() -> [UIViewController] { var viewControllers : [UIViewController] = [] self.pageControllerIdentifierList.forEach { viewControllerName in //ViewControllerのIdentifierからViewControllerを作る let viewController = UIStoryboard(name: "Main", bundle: nil) . instantiateViewControllerWithIdentifier("\(viewControllerName)")

viewControllers.append(viewController) } return viewControllers }

子のViewControllerにIdentifierをつけておく

Page 9: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ UIPageViewControllerのインスタンスの初期化〜配置まで

PageViewControllerを使用したサンプル解説

UIPageViewControllerのインスタンス生成時とsetViewControllersが実装時の大きなポイントになる!

★ViewDidLoad内で行う処理の概要は初期化と読み込まれた際の表示に関する事など

・初期化→デリゲートの設定→初めに見せるViewControllerの決定→pageViewControllerの配置

・transitionStyleやnavigationOrientationで子のViewControllerの切り替え時の見た目を設定する

override func viewDidLoad() { super.viewDidLoad() //・・・(その他の副次的な部分は省略)・・・ //UIPageViewControllerの設定 // * .Scrollだと謎のキャッシュ問題が発生 self.pageViewController = UIPageViewController(transitionStyle: .PageCurl, navigationOrientation: .Horizontal, options: nil) //UIPageViewControllerのデリゲート self.pageViewController.delegate = self self.pageViewController.dataSource = self //UIPageViewControllerの初期の位置を決める self.pageViewController.setViewControllers([PageSettings.generateViewControllerList().first!], direction: .Forward, animated: false, completion: nil) //UIPageViewControllerを子のViewControllerとして登録 self.addChildViewController(self.pageViewController) //UIPageViewControllerを配置 self.view.addSubview(self.pageViewController.view) }

引数の意味:・第1引数:ページ送りする際のスタイル設定(.PageCurl:ページめくり/.Scroll:スクロール)・第2引数:ページ送りの方向設定(.Horizontal:水平方向/.Vertical:垂直方向)・第3引数:その他オプション設定

引数の意味:・第1引数:表示対象のViewController・第2引数:アニメーション方向(.Forwardor.Reverse)・第3引数:アニメーションの有無・第4引数:完了時の処理

Page 10: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ viewDidLayoutSubViews()内で大きさを再定義する

PageViewControllerを使用したサンプル解説

AutoLayout時はUIViewControllerやUIViewのライフサイクルを利用するor制約をコードで指定して配置

★UIViewControllerのライフサイクルを利用して位置を決めていく

・AutoLayout使用時はviewDidLoadorviewWillAppear内でCGRectMakeメソッド等で位置を決められない

・本当はAutoLayoutの制約をコードで配置する方法が望ましいのかもしれない・・・

//レイアウト処理が完了した際の処理 override func viewDidLayoutSubviews() { //UIScrollViewのサイズを変更する self.menuScrollView.frame = CGRectMake(

CGFloat(0), CGFloat(PageSettings.menuScrollViewY), CGFloat(self.view.frame.width), CGFloat(PageSettings.menuScrollViewH) ) //UIPageViewControllerのサイズを変更する //サイズの想定 →(X座標:0, Y座標:[UIScrollViewのY座標+高さ], 幅:[おおもとのViewの幅], 高さ:[おおもとのViewの高さ] - [UIScrollViewのY座標+高さ]) self.pageViewController.view.frame = CGRectMake( CGFloat(0), CGFloat(self.menuScrollView.frame.origin.y + self.menuScrollView.frame.height), CGFloat(self.view.frame.width), CGFloat(self.view.frame.height - (self.menuScrollView.frame.origin.y + self.menuScrollView.frame.height)) ) self.pageViewController.view.backgroundColor = UIColor.grayColor() self.menuScrollView.backgroundColor = UIColor.lightGrayColor() //UIScrollViewの初期設定 ※コード省略・・・ //UIScrollViewへのボタンの配置 ※コード省略・・・ //動くラベルの配置 ※コード省略・・・ }

・UIPageViewControllerのライフサイクルについて:http://qiita.com/mo_to_44/items/0ca628b4cc74c8c5599d

・UIViewのレイアウト周りの処理はviewDidLayoutSubViewsの内部でやった方がいいhttp://furodrive.com/2014/10/how_to_access_iboutlet/

Page 11: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ スワイプ操作で表示するViewControllerの切り替え

PageViewControllerを使用したサンプル解説

AutoLayout時はUIViewControllerやUIViewのライフサイクルを利用するor制約をコードで指定して配置

★UIPageViewDatasourceのメソッドを活用する

・前のページに送る→viewControllerBeforeViewController

・次のページに送る→viewControllerAfterViewController

//ページを次にめくった際に実行される処理 func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { let targetViewControllers : [UIViewController] = PageSettings.generateViewControllerList() if self.viewControllerIndex == targetViewControllers.count - 1 { return nil } else { self.viewControllerIndex = self.viewControllerIndex + 1 } //スクロールビューとボタンを押されたボタンに応じて移動する self.moveToCurrentButtonScrollView(self.viewControllerIndex) self.moveToCurrentButtonLabel(self.viewControllerIndex) return targetViewControllers[self.viewControllerIndex] }

実装のポイント・メンバ変数viewControllerIndexの値をviewControllerAfterViewControllerは+1,viewControllerBeforeViewControllerは-1する・UIViewControllerのリストからメンバ変数viewControllerIndexの値のところのものを取得する・戻り値はUIViewController型になる

Page 12: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ ScrollViewで配置されているボタンでViewControllerの切り替え

PageViewControllerを使用したサンプル解説

ScrollViewとの連携も意外としやすい印象。PageViewControllerを活用して様々なUIの幅が広がると思う!

★ボタンがタップされたタイミングでsetViewControllersメソッドを呼び出す

・ScrollView内にボタンを設置するタイミングでタグを仕込みその値を活用する

・setViewControllersメソッドの第3引数をtrueにして切り替えるタイミングにページめくりをつける

//ボタンをタップした際に行われる処理 func buttonTapped(button: UIButton){ //押されたボタンのタグを取得 let page: Int = button.tag //UIPageViewControllerのから表示対象を決定する if self.viewControllerIndex != page { self.pageViewController.setViewControllers([PageSettings.generateViewControllerList()[page]], direction: .Forward, animated: true, completion: nil) self.viewControllerIndex = page //スクロールビューとボタンを押されたボタンに応じて移動する self.moveToCurrentButtonScrollView(page) self.moveToCurrentButtonLabel(page) } }

実装のポイント・ScrollView内にボタンを配置する際にタグを設定しておく・ボタンに設定したタグの値をもとに表示するViewControllerを決定する(setViewControllersでその処理を行っている)

animated:trueにして切り替えの際にアニメーション

Page 13: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ 土台となるViewControllerに2つのContainerViewを配置

ContainerViewを使用したサンプル解説

・重なり順は下から「メイン」→「メニュー」→「透明ボタン」となる

・viewDidLoad内で各々の要素に対する初期設定、viewDidLayoutSubviews内で要素の位置を再定義

それぞれのViewController同士を重ねて1つの画面内で表示したい場合にはContainerViewが活躍する!

★メニュー部分とメイン部分のContainerViewの配置と制約付けを行う

SideContentsController.swift

BaseContentsController.swift

Page 14: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ コンテンツ用のContainerViewにつながっているViewController

ContainerViewを使用したサンプル解説

・初期配置やAutoLayoutの制約に関しては上記の制約を参考にしてください

・大まかな枠組み部分はAutoLayout・ボタンの配置やScrollViewの設定についてはコードで実装

上記の方針が本当に正しいかは実際のところ自信がなかったりする…(ベストプラクティス的なものは?)

★メイン部分(BaseContentsController.swift)のパーツ配置と制約付けを行う

Page 15: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ 配置したScrollView内にContainerViewを配置する

ContainerViewを使用したサンプル解説

・AutoLayout+ScrollViewの組み合わせはハマりやすいポイントの典型例

・ContainerViewから「Control+ドラッグ」をして親のScrollViewにカーソルを当てEqualWidths(Heights)

上記の方針が本当に正しいかは実際のところ自信がなかったりする…(ベストプラクティス的なものは?)

★ScrollView内にコンテンツ用のContainerを配置する

SimulatedSizeをFreeformのwidth:3600

Page 16: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

ここでライブコーディングします!

5分間お時間をくださいm(__)m

Page 17: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ 自力での実装に疲れそうなら進んで活用すべし!

UI系で気になるライブラリピックアップ

開発者の方々には本当に感謝しております!一同、素晴らしい開発者の皆様に礼!(おれもいつかは作る!)

★UIまわりのライブラリ4選

・RMPScrollingMenuBarController

https://github.com/recruit-mp/RMPScrollingMenuBarController

http://tech.vasily.jp/entry/tab_page_viewcontroller

・PagingMenuController

https://github.com/kitasuke/PagingMenuController

・PageMenu

https://github.com/HighBay/PageMenu

・TabPageViewController

https://github.com/EndouMari/TabPageViewController

<上記に関する紹介記事的なもの>

・UIPageViewControllerをつかって無限スクロールできるタブUIを実装してOSSとして公開しました

http://animane.hatenablog.com/entry/2015/09/27/133859

・SmartNewsのようなUIを実現するライブラリ3つを比較してみた

Page 18: UIPageViewControllerとContainerViewでこんな見た目を実現するTips

✦ 本にはなかなか載ってない部分だけど活用できると面白い!

今回のまとめ

ご清聴ありがとうございました!またこのような機会があった際には是非ともよろしくお願い致します!

★UIPageViewControllerやContainerViewを知ると気になるUI実装へ近づく

・自力での実装orライブラリ活用の選択に関する決め手の落とし所は引き続き研究中…

・UI系の優れたライブラリのコードを読むと実装のヒントやUIKitへの理解が深まるので面白いです

それぞれの持つ特徴や特性を公式リファレンス等で確認しておくと役に立つ

★AutoLayoutやUIViewControllerのライフサイクルに関しても確認

AutoLayoutでの制約のつけ方の理解やライフサイクルへの理解も重要ポイント

★はまりやすいレイアウトの事例についても事前に知っておく

ScorllViewとAutoLayoutの組み合わせ等の定番ものがあったりするので注意が必要

★UI系のライブラリの実装方法や中のコードについても見てみる

知っておくと役に立つ&汎用的なものも数多くあるのでチェックしておく