wootan's diary

iOSアプリ開発を中心としたエンジニアブログ

relux iOSアプリにNavigationDrawerを実装

relux iOSアプリにNavigationDrawerを実装しました。
いくつかライブラリも検討したのですが、条件に会うものがなくスクラッチ開発しました。
その時に気をつけたことや工夫したことを紹介したいと思います。

NavigationDrawerとは?

f:id:wootan1102:20160408021018g:plain

画像のように左側からスライドして表示されるメニューがNavigationDrawerです。
詳しくはGoogle design guidelinesを参照
Navigation drawer - Patterns - Google design guidelines

求める要件

  • Androidと同じような挙動になること
  • デザインを自由に変更できること
  • メニューの順序を簡単に変更できること
  • 画面端をスワイプした際に指についてくること
  • メンテナンスされていること(最新のiOSに対応していること)

レイアウト

レイアウトはあとから変更になる可能性が高いので
Storyboard(AutoLayout)を使用しています。


左側のメニュー部分はUITableView、右側の透過している部分はUIViewです。
透過している部分はTouch時にドロワーメニューを閉じるようになっています。

ユーザ情報セル

背景画像は季節毎に変更できるようにサーバから取得するようにしています。
頻繁に変わるものではないですが変更した際にすぐに反映させたかったので
画像のキャッシュ期間は1日としています。
ここでは画像の上に文字をのせるので視認性をあげるためにグラデーションをかけています。

// グラデーションをかける処理 UITableViewCellなどでは複数回呼ばれないように注意
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);
gradient.colors = @[
  (id)[UIColor clearColor].CGColor,
  (id)[UIColor blackColor].CGColor
];
[view.layer addSublayer:gradient];

イコン画像は丸くトリミングし、名前と会員IDをアイコンの横にならべて表示しています。

// 画像を丸くトリミング
view.layer.cornerRadius = view.frame.size.width * 0.5f;
view.clipsToBounds = YES;

名前のフォントサイズはかなり大きめに設定していますが
スペースを十分に設けているので実機でみると違和感はありませんでした。

メニューセル

メニューのアイコンはGoogleのMaterial iconsを使用しています。
Androidアプリでよく使われるアイコンですがiOSで使用しても違和感はありません。
ただし、システムアイコンとならべるとボーダーが太いので気をつける必要があります。
design.google.com

メニューセルではRippleEffect(波紋アニメーション)はあえてつけませんでした。
技術的にはつけることは可能なのですが、
iOSらしくない動きであること
古い端末を考慮するとスペック的に厳しいことから実装しませんでした。

レイアウト順序

メニュー部分のレイアウト順序は追加・変更になることがわかっていたので
担当エンジニア以外でも簡単に変更できるように定数で持っています。

#define NAVIGATION_DRAWER_USER_INFO_ROW                  0
#define NAVIGATION_DRAWER_USER_BOOKING_CONFIRMATION_ROW  1
#define NAVIGATION_DRAWER_USER_FAVORITE_ROW              2
#define NAVIGATION_DRAWER_USER_HISTORY_ROW               3

スピード優先で実装しているとハードコーディングしてしまいがちですが
あとで困るのは自分なので こういう部分は意識して定数にするようにしています。

CustomTransitionの実装

今回使用したのは以下になります。

UIViewControllerAnimatedTransition

  • transitionDuration
  • animateTransition

UIPanGestureRecognizer

UIPercentDrivenInteractiveTransition

実装方法についてはAppleドキュメントに記載されているので
紹介はしませんが工夫した点があるので紹介します。
developer.apple.com

指にあわせて動かす工夫

実装時に一番苦労した部分でもあります。
右側の透過部分を含めて1画面としているので
そのまま実装してしまうと指についてこないように見えてしまいます。

そこで画面の幅から計算して擬似的に指についてくるように実装しました。
offset分だけずらしてcontrollerの横幅で除算することで割合を算出しています。

case UIGestureRecognizerStateChanged: {
  CGFloat width = controller.view.bounds.size.width;
  CGFloat fraction = MAX([gesture translationInView:controller.view].x + offset, 0) / width;
  if (fraction > 1.0f) {
    fraction = 1.0f;
  }
  _shouldCompleteTransition = fraction > INTERACTION_THRESHOLD;
  [self updateInteractiveTransition:fraction];
}

やってみて感じたこと

今までCustomTransitionはあまり使っていなかったのですが、実装してみるとそんなに難しくありませんでした。
CustomTransitionを実装るすことによって他のアプリとは違った動きになるので、他の画面でもどんどん取り入れていきたいと考えています。

良かったら実際のアプリを触ってみてください!
いつものreluxを、アプリでも。 | relux