【iOS】スクロール可能なメニューバーを持つViewControllerをオープンソースとして公開しました
大島 雅人
概要
スクロールできるメニューバーとスワイプで画面を切り替えることができるViewControolerのコンテナを、オープンソースとして公開しました。
We published RMPScrollingMenuBarController by open source.
RMPScrollingMenuBarController has a scrollable menu bar, and multiple view controllers for iOS.
ニュース系アプリでよく使われているUIで、弊社の料理サプリのiOSアプリのトップ画面でも使用しています。
何はともあれこちらのgifアニメをを見てもらったら分かると思います。
自己紹介
本記事がはじめてなので本題の前に少し自己紹介を。
リクルートマーケティングパートナーズのiOSエンジニアの大島雅人と申します。
前職はSIerでBtoB向けiPadアプリの開発をしていましたが、プログラマに特化してキャリアを積んでいきたいと思い、今年1月に転職しました。入社して数日でいきなりブログ書いてますが、このライブラリは僕が作った訳ではなく、yshrktさんが作ったものです。yshrktさんがブログは書きたくないって言ってるwので、僕が代わりに書いています。今流行りのゴーストライターです。
特徴
グノシー、SmartNews、はてなのPressoなどで使われている最近流行りのUIですが、実はUIKitやオープンソースのライブラリとしては提供されていませんので、このプロジェクトが初じゃないかな?と思います。 UIKit標準では提供されていません。
View構造
このライブラリのポイントは、メニューバー部分はUIScrollView
で作っていますが、コンテンツ部分は複数のUIViewController
のセットでできているということです。コンテンツ部分もUIScrollView
で作ってしまうと、各画面の処理を分割しにくく、iOS開発にありがちな巨大なViewControllerになってしまいます。各コンテンツをViewControllerのセットとして管理することで、UITabBarController
のように子画面に分割することができ、既存のUIViewController
の画面をそのまま生かすこともできます。
コンテンツ部分のスクロールの実現方法
一方で、じゃあコンテンツ部分にUIScrollViewを使わないということは、スクロール処理はどうやるの?という疑問が湧いてくるかと思います。ここがもう一つのポイントで、UIViewControllerInteractiveTransitioningを使って実装しています。遷移前の画面と遷移後の画面にそれぞれ始点と終点を指定してアニメーションを設定しておきます。あとは、ドラッグのジェスチャーであるUIPanGestureRecognizer
をaddしておいて、そのイベントを取得してアニメーションの時間(timeOffset
)を変更するようにしています。これによってスクロールビューのようなUIを実現しています。
ビューの変更なのに時間をずらすというのはちょっとわかりにくいかもしれませんが、YouTubeなどで動画を見ているときに一時停止状態で再生位置を少しずつずらしているイメージです。(遷移前と遷移後のアニメーションのイメージを図にしておきました。)いやー、すごい。この発想はなかなかできないです。僕は、てっきりスワイプのタッチ位置をとって、その都度viewの位置を計算して少しずつずらしているのかと思っていました。
ライブラリの使い方
初期化
使い方はGitHubにも書いていますが、cocoapods経由でインストールできます。
pod RMPMenuBarController
セットアップ方法はオブジェクトを初期化して、UITabBarController
のようにUIViewController
の配列をセットするだけです。簡単ですね!
RMPScrollingMenuBarController* menuController = [[RMPScrollingMenuBarController alloc] init];
menuController.delegate = self;
NSArray* viewControllers = @[vc1, vc2, vc3, vc4, vc5];
[menuController setViewControllers:viewControllers];
UINavigationController* naviController;
naviController = [[UINavigationController alloc] initWithRootViewController:menuController];
メニュー名の生成とイベント通知
メニュー名はdelegateメソッドで設定します。初期値として配列を渡すようなアーキテクチャではなく、delegateメソッドで設定することで状況に合わせて変更できる設計にしています。
- (RMPScrollingMenuBarItem*)menuBarController:(RMPScrollingMenuBarController *)menuBarController
menuBarItemAtIndex:(NSInteger)index
{
RMPScrollingMenuBarItem* item = [[RMPScrollingMenuBarItem alloc] init];
item.title = [NSString stringWithFormat:@"Title %02ld", (long)(index+1)];
return item;
}
選択中のviewControllerやindexなどはプロパティとして取得できます。
/** Selected view controller.
*/
@property (nonatomic, weak)UIViewController* selectedViewController;
/** Index of selected view controller.
*/
@property (nonatomic, assign)NSInteger selectedIndex;
メニューの選択やスワイプでの画面の切り替わりの通知を受け取ることができます。メニュー経由でもスワイプでも同じです。
// 1. 画面を切り替えて表示しようとしている画面
- (void)menuBarController:(RMPScrollingMenuBarController *)menuBarController
willSelectViewController:(UIViewController *)viewController
{
NSLog(@"will select %@", viewController);
}
// 2. 切り替わったあと表示されている画面の通知
- (void)menuBarController:(RMPScrollingMenuBarController *)menuBarController
didSelectViewController:(UIViewController *)viewController
{
NSLog(@"did select %@", viewController);
}
// 3. 切り替えようとしたけどやっぱり元の画面に戻ったときの通知
- (void)menuBarController:(RMPScrollingMenuBarController *)menuBarController
didCancelViewController:(UIViewController *)viewController
{
NSLog(@"did cancel %@", viewController);
}
使い方はそれほど難しくないと思いますが、詳細はGitHubにExampleプロジェクトがあるのでそれで確認していただければと思います。
ライセンス
MIT
最後に
このライブラリを使って新しいUIに修正した料理サプリをversion 3.0.0として公開しています。個人的にはいつか行ってみたいなと思っていた賛否両論の笠原さんのレシピ動画が載っててこりゃすごいな1)もちろん他の方もすごい有名人ばかりですがと思いました!鶏のしゃぶしゃぶとか超うまそう。
コントリビュートもお待ちしていますので、お気軽にプルリクなどして頂ければと思います!
脚注
↑1 | もちろん他の方もすごい有名人ばかりですが |
---|