pixiv insideは移転しました! ≫ http://inside.pixiv.blog/

Swift+CocoaPodsではじめてのOSS(ハンバーガーメニューを作ってみた)

ピクシブ株式会社 Advent Calendar 2016 @5日目です。

新卒のkpです。昨年までアルバイトとしてpixiv、pixiv touch、pixiv Spotlight (現 pixivision)に、現在は創作したものを販売できるWebサービスのBOOTHに携わっています。

ハンバーガーメニューをライブラリ化してCocoaPodsに登録した

Webサービスのスマートフォン版表示や、iOS/Androidアプリでよく見るUIの一つにハンバーガーメニューがあります。三本の水平線で表され、画面の隅にあり、タップすることで隠れているメニューを呼び出すものです。

しかし、SwiftのUIKitには、ハンバーガーメニューと呼ばれるコンポーネントの実装がありません。 解決方法は大きく分けて2種類あります。 一つは、UIPresentationControllerや、UIViewControllerAnimatedTransitioningなどを使って手作業で実装していく方法です。 もう一つは、ライブラリによる解決です。Swiftには、CocoaPodsというライブラリ管理プラットフォームがあります。しかし、登録してあるライブラリはトランジションが派手なライブラリが多いように感じました。シンプルな実装を求めていたので、この機会に、既存のアプリケーションから該当部分を切り出してライブラリ化し、CocoaPodsに登録してみました。

ライブラリ化することで、プロジェクトを分割して小さくでき、再利用が容易になり、更にビルド時間の短縮にもつながります。本エントリでは自作ライブラリをCocoaPodsに登録する方法について紹介させて頂きます。

今回開発したライブラリはGitHubで公開しています。 keisei1092/PlainMenuController

空のCocoaPodライブラリを作る

ターミナルで、任意のディレクトリに移動して以下のコマンドを実行します。

gem update --system
gem install cocoapods
pod lib create PlainMenuController

pod lib createを実行すると言語やテストフレームワークの有無についていろいろ聞かれます。

f:id:keisei_1092:20161205142008p:plain

終了すると自動でXcodeで該当ディレクトリがオープンします。 現時点(2016/12/04)だとテンプレートが古く (~ Swift 3.0) 、Convert Syntaxダイアログが出てきます。ダイアログが出た場合は、メニューからConvert→Swift 3.0→Next→Saveを選択することで、警告を解消できます。

コードを書く場所は、

Pods/Development Pods/(ライブラリ名)/(ライブラリ名)/Classes/

になります。ここにReplaceMe.swiftというファイルがありますがこれはクラスの置き場所を示しているだけの空ファイルのため、削除しても問題ありません。

既存アプリケーションからコードを切り出す 今回は最小のライブラリ化として、UIPresentationControllerクラス、UIViewControllerAnimatedTransitioningプロトコルを切り出しました。 動いている既存アプリケーションから該当クラスをライブラリ用のディレクトリに移動しました。

ハマりそうなところとしては、モジュール外からもアクセスできるようにクラスやメソッドのaccess levelにopenを付与する必要があります。この手順を踏まないとExamples配下のクラスから呼ぶ際にunresolved identifierエラーになります。

(実際のクラスはこちら: MenuPresentationController, MenuPresentationAnimator

コードを切り出したら、メニューを呼び出すViewControllerに

import (ライブラリ名)

を追加し、呼び出し先のUINavigationControllerのtransitioningDelegateをselfにします。

let storyboard = UIStoryboard.init(name: "MenuTableViewController", bundle: nil)
let menuTableViewController = storyboard.instantiateInitialViewController() as! MenuTableViewController
let presentingNavigationController = UINavigationController(rootViewController: menuTableViewController)
presentingNavigationController.modalPresentationStyle = .custom
presentingNavigationController.transitioningDelegate = self
navigationController?.present(presentingNavigationController, animated: true, completion: nil)

最後に、このViewControllerにextensionとしてUIViewControllerTransitioningDelegateを実装し、MenuPresentationControllerを返すようにします。

extension ViewController: UIViewControllerTransitioningDelegate {


    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        return MenuPresentationController(presentedViewController: presented, presenting: presenting)
    }


    func animationController(forPresented presented: UIViewController,
                             presenting: UIViewController,
                             source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return MenuPresentationAnimator(isPresentation: true)
    }


    func animationController(forDismissed dismissed: UIViewController)
        -> UIViewControllerAnimatedTransitioning? {
            return MenuPresentationAnimator(isPresentation: false)
    }


}

下のGIFは、ここまでで実装したハンバーガーメニューの動作です。

f:id:keisei_1092:20161205142028g:plain

一旦実装はここまでとします。

ライブラリをCocoaPodsに登録する

CocoaPodsにこのライブラリを登録してみます。登録する前に、ライブラリの説明文をデフォルトから書き換えておきます。プロジェクトディレクトリ配下のPlainMenuController.podspecのsummaryを任意の文に置き換え、authorのURL内にGitHubのidを入れておきます。

Pod::Spec.new do |s|
  s.name             = 'PlainMenuController'
  s.version          = '0.1.0'
  s.summary          = 'Basic, and essential slide menu.' # changed


…


  s.homepage         = 'https://github.com/keisei1092/PlainMenuController' # changed
  s.source           = { :git => 'https://github.com/keisei1092/PlainMenuController.git', :tag => s.version.to_s } # changed


...

ファイルを保存したら、このpodspecの検証を走らせます。

pod lib lint PlainMenuController.podspec

 -> PlainMenuController (0.1.0)

PlainMenuController passed validation.

検証が通ったら、いよいよリリース作業です。最新コミットにtagをつけ、CocoaPodsユーザ登録を済ませると、pushコマンドが通るようになります。

pod trunk register (メールアドレス) '(名前)’ # => リンクが送信されるのでCocoaPodsに登録
pod trunk push PlainMenuController.podspec


Updating spec repo `master`


Validating podspec
 -> PlainMenuController (0.1.0)


--------------------------------------------------------------------------------
 🎉  Congrats


 🚀  PlainMenuController (0.1.0) successfully published
 📅  December 4th, 00:16
 🌎  https://cocoapods.org/pods/PlainMenuController
 👍  Tell your friends!
--------------------------------------------------------------------------------

今回開発したライブラリはGitHubで公開しています。 keisei1092/PlainMenuController

今後

現時点では、メニューが左からしか出せなかったり、まだ実装側のViewControllerでUIViewControllerTransitioningDelegateプロトコルを実装しなければいけなかったりと使いにくい点が多々あります。またライブラリとしてテストフレームワーク (Quickなど) の導入もやりたいところです。自分の開発を進めながら他の開発者の役に立てるというのは素晴らしいことなので、これからもガンガンコミットを生やして使ってもらえるものにしていきます。