Android だと Eclipse でプロジェクトを作成する際に「Navigation Type」で「Tabs + Swipe」を選択すれば自動的にタブをスワイプで移動できるアプリケーションができあがる。
で、このタブ間をスワイプで移動するのが思いのほか気に入ったので iOS 7でもやってみた。


もちろん、Xcode のプロジェクト作成時に「Tabbed Application」を選んでもスワイプ対応はしてくれないので、そこの部分はネットで見つけたライブラリ「VCTransitionsLibrary」にお世話になってみた。


拙作「ねむスタ」に「VCTransitionsLibrary」を試しに組み込んでみた様子はこんな感じ。

以下、VCTransitionsLibrary の使い方のメモ。

VCTransitionsLibrary をダウンロード

GitHub のページはここ。

ダウンロードして zip ファイルを展開するとこんな感じ。

フォルダに同梱されている「TabBarDemo」と「TransitionsDemo」はデモプロジェクト。
それぞれのフォルダに入っている「.xcodeproj」ファイルをダブルクリックして Xcode を起動、そのまま Run すればシミュレータなり実機なりでデモを確認することができる。
まずは「TransitionsDemo」の方で「VCTransitionsLibrary」の各種機能を確認してみるのがお勧め。

VCTransitionsLibrary を実際に使ってみる

タブ間の遷移をスワイプで行いたかったので、今回はタブを使ったアプリケーションで使ってみる。
以下簡単な手順。


1. まずは普通に Xcode で「Tabbed Application」を作成。


2. 次に VCTransitionsLibrary のフォルダから「AnimationControllers」と「InteractionControllers」をプロジェクトにコピー。


3. 次に作成したプロジェクトに VCTransitionsLibrary の TabBarDemo フォルダの中から abBarViewController.h/.m をコピー。


4. プロジェクトのファイルはこんな感じになっているはず


5. 次に Main.storyboard を開いて、UITabBarController を選択。
Identity Inspector の Custom Class で Class を TabBarViewController に変更。


以上で、タブ間の移動をスワイプでできるようになる。簡単!
(ついでに、移動時のアニメーションが折り畳む感じのものになっている。)

VCTransitionsLibrary を少し修正

VCTransitionsLibrary の肝は iOS 7 から使えるようになった UIPercentDrivenInteractiveTransition クラスと UIViewControllerAnimatedTransitioning プロトコル
この2つを上手に組み合わせて ViewController 間の遷移を行なっている。
(というわけで、実際には Tab間の遷移をスワイプでできるようにする用途のライブラリではない…)


のだけど、実際に使ってみると幾つかおかしな部分があったので修正を加えてある。


スワイプの動作が最初のタブ(View)でしか効かない
最初のタブから次のタブへスワイプで移動できるけど、移動先のタブからその先、もしくは戻ってくるスワイプが効かない。
ただし、タブバーでタブを選択してタブ間の移動を行なうと、移動した先から別のタブへのスワイプは効く。
なんとなくスワイプで移動した場合には移動先の ViewController でジェスチャーが効いてないんじゃないかな?と思ったのだけど、GitHub にある修正を行なったらちゃんと動作するようになった。

これでこの問題は解決!


スワイプの向きが反対になることがある
良くあるのが、最初のタブから次のタブへ遷移して、更に先へ行こうとすると逆に元に戻っちゃう。
これも GitHub で報告されているコードを加えたら問題が起きなくなった。

具体的には CEHorizontalSwipeInteractionController.m をこんな感じに。

- (void)handleGesture:(UIPanGestureRecognizer*)gestureRecognizer {
    CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view.superview];
    CGPoint vel = [gestureRecognizer velocityInView:gestureRecognizer.view];

    switch (gestureRecognizer.state) {
        case UIGestureRecognizerStateBegan: {
            BOOL rightToLeftSwipe = vel.x < 0;


移動先が NavigationController の画面の場合、Fold のアニメーション中の画面はステータスバーが含まれていない状態なのでアニメーション終了時に画面全体がステータスバーの分だけ下にピョコっと下がる
これはとっても気持ちが悪い…。
VCTransitionsLibrary では遷移のアニメーションを作る際に遷移先の画像を作成するのだけど、ここで使っている -(UIView *)resizableSnapshotViewFromRect: afterScreenUpdates: withCapInsets: で得られる画像にはステータスバーが入っていない。なので、アニメーション中の画像はステータスバーがない状態(上に詰まった状態)で表示されてしまう。


どうしたらステータスバーが入った状態の画像を得られるのかわからなかったので(なんとなくIBでの設定とかでなんとかなりそうな気もするのだけど…)、今回は強引にこの部分を書き換えてしまった。
具体的には、遷移先の View が NavigationBar を持っていたらスナップショット作成するときにステータスバーの分だけ下に貼付けるようにした。
これだけではステータスバーの部分が黒くなってしまうので、snapshotView の background を NavigationBar.barTintColor もしくは白で塗りつぶしておく。


CEFoldAnimationController.m の 142行目以降をこんな感じに。

NSArray * subViews = view.subviews;
BOOL haveNavigationBar = NO;
UIColor *bgColor;

for (UIView *aView in subViews) {
	if ([aView isMemberOfClass:[UINavigationBar class]]) {
		haveNavigationBar = YES;
		bgColor = ((UINavigationBar *)aView).barTintColor;
		if (bgColor==nil) {
			bgColor = [UIColor whiteColor];
		}
	}
}

if (haveNavigationBar) {
	snapshotView.backgroundColor = bgColor;
	snapshotRegion = CGRectMake(offset, -20.0, foldWidth, size.height-20.0);
}
else {
	snapshotView.backgroundColor = view.backgroundColor;
	snapshotRegion = CGRectMake(offset, 0.0, foldWidth, size.height);
}

これで、先の動画のような動きをするようになった。

VCTransitionsLibrary を使ってみて

ここから更にタブをタップした時にはアニメーション無しで遷移させたいな〜とか、もっとあっさりとしたアニメーションにしたいな〜とか考えると、実際にこのライブラリを使うよりも自分で書いちゃった方が早いような気がする。
というか、このライブラリは「iOS7 になってこんなことが簡単にできる様になったよ!」ということを教えてくれる見本かな。
というわけで「Tabs + Swipe」なアプリケーションを作ったりカスタムな遷移方法を作る方法としてはとっても参考になりました!