どこまでも分かりやすいスワイプ画面作成方法

  • 33
    Like
  • 0
    Comment
More than 1 year has passed since last update.

はじめに

Google MapやFaceBookアプリのように、右側にスワイプするとレフト画面が表示されるUIを作成します。

2画面を重ねて表示させてい場合はスワイプ専用のViewを作成し、
上下にメイン画面(MainCV)とレフト画面(LeftCV)が表示されるよう設定します。

その際に使われるのがContainer View Controllerです。
今回はContainerと操作に必要なパーツを乗せて、実装していきます。

手順

  1. Storyboardから必要なViewの配置
  2. ユーザーの操作設定
  3. Navigation Controllerの設定
  4. UIを制御するコードの記述

Storyboardから必要なViewの配置

  1. ContainerをObject Libraryから2つドラッグし、View Controllerへドロップする
  2. 同様にViewをView Controllerへドロップする
  3. わかりやすくするために名前を変更する

04.png

今回は名前を以下のように設定しました。

  • Main CV → メイン画面を乗せるためのContainer View Controller
  • Left CV → レフト画面を乗せるためのContainer View Controller
  • Cover View → 画面を移動させたときに上の画面を覆うView

現在のエディタエリアは以下のようになっています。
わかりやすいようにViewに色をつけています。
02.png

このままではCover Viewが全体を覆っているため、後ろのUIが表示できません。
そこで

  1. Document OutlineからCover Viewを選択
  2. Editor EreaのAttribute InspectorからViewのBackgroundをClear Colorに設定
  3. User Interaction Enabledのチェックを外す

05.png
必要なViewの配置は以上です。

ユーザーの操作設定


次に、ユーザーの操作に反応させていきます。
タップやスワイプのイベントに反応するためにGesture Recognizerを配置していきます。
  1. Tap Gesture RecognizerをObject Libraryからドラッグし、Document OutlineのCover Viewへドロップする
  2. 同様にObject LibraryからSwipe Gesture Recoginizerを2個Viewへドロップする
  3. わかりやすくするために名前を変更する

08.png

Swipe Gesture Recoginizerは初期状態で右へ動くよう設定されています。
レフト画面からメイン画面に戻りたい場合、右側にあるメイン画面を左側にスライドさせたいので、

  1. Document OutlineのLeftSwipedを選択し、Attribute InspectorからSwipeをLeftに設定する

09.png
これで、Swipeの設定は以上です。

Navigation Controllerの設定


Container View ControllerとView Controllerの間にNavigation Controllerを設置します。
  • Document OutlineからLeft VCを選択
  • ツールバーからEditorを選択し、Embed In → Navigation Controllerをクリック

10.png

Editor Ereaは以下のようになります。
11.png

今回、レフト画面はメニューを表示させたいので、Table View Controllerに変更します。

  1. Object LibraryからTable View Controllerを適切な場所へドラッグ&ドロップ
  2. Navigation ControllerからTable View Controllerへセグエを繋げる
  3. 不必要になったグレー背景のView Controllerを削除

ユーザーの操作設定は以上です。

UIを制御するコードの記述

UI要素をコードへ接続していきます。

現在のView名をわかりやすくする


ソースコードを実装する前に、現在のView名をわかりやすくしましょう。

14.png
15.png

各Viewにクラスを指定

今回は3つのviewを使用しているので、3つクラスを用意します。
既にあるViewController.swiftはContainerVCの処理を記述したいので、新しくMainVC.swiftとLeftTV.swiftを作成します。

  • Container VC → ViewController.swift(既存のものを使用)
  • Main VC → MainVC.swift
  • LeftTV → LeftTV.swift

20.png

作成したらインスペクタペインからそれぞれのクラスを対応させましょう。

View Controllerへ接続

まずはView ControllerにMainstoryboardのDocument Outlineから

  • Main CV
  • Left CV
  • Cover View

を接続させます。
ViewController
@IBOutlet weak var MainCV: UIView!
@IBOutlet weak var LeftCV: UIView!
@IBOutlet weak var CoverView: UIView!

次にスワイプした際に反応するよう、

  • Tap Gesture Recognizer
  • LeftSwpied
  • RightSwpied

を記述します。
ViewController
    @IBAction func coverTapped(sender: AnyObject) {
    }
    @IBAction func leftSwiped(sender: AnyObject) {
    }
    @IBAction func rightSwiped(sender: AnyObject) {
    }

スワイプした際に動く範囲やアニメーション方法を指定したいので、メソッドを指定します。

  • showBackground() → LeftTV画面を表示させるために右に画面をズラすメソッド
  • hideBackground() → MainVC画面を再表示させるために左に画面を戻すメソッド
ViewController
    @IBAction func coverTapped(sender: AnyObject) {
        hideBackground()
    }
    @IBAction func leftSwiped(sender: AnyObject) {
        hideBackground()
    }
    @IBAction func rightSwiped(sender: AnyObject) {
        showBackground()
    }

追加したプロパティで、LeftTV画面が見えているときに固定させます。

ViewController.swift
    var isBackgroundVisible = false
ViewController
    func showBackground() {
        if (self.isBackgroundVisible) { return }
        self.isBackgroundVisible = true

        UIView.animateWithDuration(0.3, animations: { () -> Void in
            self.MainCV.frame = CGRectOffset(self.CoverView.frame, 230, 0)
            }, completion: nil)
        self.CoverView.frame = CGRectOffset(self.CoverView.frame, 230, 0)
        self.CoverView.userInteractionEnabled = true
    }

    func hideBackground() {
        if (!self.isBackgroundVisible) { return }
        self.isBackgroundVisible = false

        UIView.animateWithDuration(0.3, animations: { () -> Void in self.MainCV.frame = CGRectOffset(self.CoverView.frame, -230, 0)}, completion: nil)
        self.CoverView.frame = CGRectOffset(self.CoverView.frame, -230, 0)
        self.CoverView.userInteractionEnabled = false
    }

MainVCとLeftTVにも接続

最後にMainVCとLeftTVにもshowBackgroundMenu関数とhideBackgroundMenu関数を記述します。

MainVC.swift
    func showBackgroundMenu() {
    }

    func hideBackgroundMenu() {
    }
LeftTV.swift
    func showBackgroundMenu() {
    }

    func hideBackgroundMenu() {
    }

ソースコード一覧

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var MainCV: UIView!
    @IBOutlet weak var LeftCV: UIView!
    @IBOutlet weak var CoverView: UIView!

    @IBAction func coverTapped(sender: AnyObject) {
        hideBackground()
    }
    @IBAction func leftSwiped(sender: AnyObject) {
        hideBackground()
    }
    @IBAction func rightSwiped(sender: AnyObject) {
        showBackground()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let rightGesture = UISwipeGestureRecognizer(target: self, action: "rightSwiped:")
        let leftGesture = UISwipeGestureRecognizer(target: self, action: "leftSwiped:")
        let tapGesture = UITapGestureRecognizer(target: self, action: "coverTapped:")
        leftGesture.direction = .Left
        self.view.addGestureRecognizer(rightGesture)
        self.view.addGestureRecognizer(leftGesture)
        CoverView.addGestureRecognizer(tapGesture)
    }

    var isBackgroundVisible = false

    func showBackground() {
        if (self.isBackgroundVisible) { return }
        self.isBackgroundVisible = true

        UIView.animateWithDuration(0.3, animations: { () -> Void in
            println(self.CoverView.frame)
            self.MainCV.frame = CGRectOffset(self.CoverView.frame, 230, 0)
            }, completion: nil)
        self.CoverView.frame = CGRectOffset(self.CoverView.frame, 230, 0)
        self.CoverView.userInteractionEnabled = true
    }

    func hideBackground() {
        if (!self.isBackgroundVisible) { return }
        self.isBackgroundVisible = false

        UIView.animateWithDuration(0.3, animations: { () -> Void in
            self.MainCV.frame = CGRectOffset(self.CoverView.frame, -230, 0)
            }, completion: nil)
        self.CoverView.frame = CGRectOffset(self.CoverView.frame, -230, 0)
        self.CoverView.userInteractionEnabled = false
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func todoListVCDidTapeditButton(VC: MainVC) {
        self.showBackground()
    }
    func leftViewDidSelectCell(cellNumber: Int) {
        self.hideBackground()
    }
}

AutoLayoutでcoverViewがズレているとへんな動きになるので、AutoLayoutの指定を間違えないようにしてくださいね。

以上です。