この記事はiOS Advent Calendar 2017 6日目の記事です。
ドロワー?
(だいぶ前からですが・・・)iOS10/11からApple純正マップアプリのデザインが変わり、
画面下部に角丸ドロワーが使われるようになりました。
マップアプリのような全画面表示を前提とするアプリと相性が良い感じがしますね。
ただ残念ながらAppleはこのUIを提供していないため、自前で用意する必要があります。
それで近いものを作ろうとしてできたのがこちら。
サンプルということでライブラリを使用せず、シンプルに。
ちなみに🍣を回す意味は特にないです。
やったこと
薄暗い背景Viewとドロワーを詰めたDrawerViewを作成し、Storyboardに貼り付けます。
ドロワー内に表示するコンテンツは別にDrawerContainerViewとして分けます。
UIPanGestureRecognizerを用いてドロワーの移動処理を行い、移動後の位置から背景色のalpha値を変更します。
移動の際のバウンスなんかができていませんが、そこはサンプルということで何卒・・・😱
@IBAction func didPanGesture(_ sender: Any) {
guard let recognizer = sender as? UIPanGestureRecognizer else {
return
}
let translation = recognizer.translation(in: self)
switch (recognizer.state) {
case .began:
// ドラッグし始めた時の位置を保存
self.savedDrawerBottomConstant = self.drawerBottomConstraint.constant
case .ended:
// 終了
if translation.y >= 0 {
self.close()
} else {
self.open()
}
default:
// ドラッグ中
var offset = CGFloat(self.savedDrawerBottomConstant - translation.y)
if offset > 0 {
offset = 0
}
// ドロワーの表示位置を変更
self.drawerBottomConstraint.constant = offset
// 背景色の変更アニメーションを適用
self.animateBackgroundColorIfNeeded()
}
}
詰まったところ
UIViewを被せる形になるので、そのままだと下にあるマップのタップやスクロールができません。
そこで、pointInside:withEventをオーバーライドし、タップされた位置からタップイベントを下のViewに通すかどうか判定を行うようにしました。
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
// drawerView内のタップイベントを通さない
if drawerView.frame.contains(point) {
return true
}
// drawerViewが開いている時はタップイベントを通さない
if backgroundView.frame.contains(point) && self.backgroundViewAlpha != 0.0 {
return true
}
return false
}
感想
寿司がたべたいなと思いました。
シンプルにできる方法を考えたらこんな感じになりました。もっといい方法がありそう。
あと調べたらこれ系のドロワーがライブラリとして公開されていました。純正マップ寄りで良さそうですね。