web-dev-qa-db-ja.com

スライドサイドバーメニューIOS 8 Swift

IOS Swiftサードパーティライブラリなしで、Side Sidebar Menu(Facebookアプリのような)を実装する方法はありますか? Objective-Cに実装された機能。

38
Naldo Lopes

IOS8で大幅に更新されたUISplitViewControllerフォームを開始できると思います。セッションの監視 iOS8のコントローラーの進歩の表示 および IKitを使用したアダプティブアプリの構築 詳細 2番目のセッションのコード例 を提供します(ただし、最初のセッションは形成しません:/)。この時点で、iOS8のSplit View Controllerに基づいてこの種のUIを作成するのは自然なことです。

更新:彼らが話しているすべてのAPIがまだ上陸していないようです。ビデオで言及されている現在のベータ4では、例えばBarsOnSwipeは表示されません。

17
Ilya Belikin

Update:この回答ではなく、更新された回答の使用を検討してください。 Scrollview/Container Viewアプローチには、カスタムビューコントローラートランジションを代わりに使用することで回避できる多くのEdgeケースがあります。

ライブラリを必要としないSwiftメニューソリューションを探しました。Fengsonのアプローチとかなり似た、独自のチュートリアルを作成することになりました。

enter image description here

主なポイントは次のとおりです。

  • メニューのスライド動作とパンジェスチャを処理するscrollviewを作成します
  • container内に、2つのscrollviewビューを並べて配置します。コンテナを使用すると、トップレベルのコントローラーを埋め込むことができます。
  • scrollviewで、paging enabledを設定しますが、bouncesを無効にします。これにより、スライドアウトが強制的に開いた状態または閉じた状態になります
  • embed a UITableViewControllerは左のコンテナにあります
  • embed a UITabBarControllerは右のコンテナにあります
  • 右側のcontainerに、0.8のランタイム属性layer.shadowOpacityを追加します。これにより、コードなしで無料のシャドウセパレーターが提供されます。
  • メニューボタンを追加します。 NSNotificationCenterを使用して、scrollviewと通信できます。
  • 秘密の材料の場合:scrollView.setContentOffset.xを使用して、メニューの実際の開閉を処理します

以下に、スクリーンショットと手順を含む、左のスライドアウトメニューを備えたタブバーアプリケーションの実用的なプロジェクト例を示します。

https://github.com/ThornTechPublic/LeftSlideoutMen

それがどのように機能するかについてのより一般的な説明とともに:

http://www.thorntech.com/2015/06/want-to-implement-a-slideout-menu-in-your-Swift-app-heres-how/

16
Robert Chen

IOS7およびiOS8のスライドサイドバーメニュー、Swiftコーディング。

NavigationController levelで必要な場合(背後のすべてのViewコントローラーの場合):

https://github.com/evnaz/ENSwiftSideMen

ただ1つにしたい場合ViewController

ビデオ: https://www.youtube.com/watch?v=qaLiZgUK2T

ソースコード: http://goo.gl/ULWxJh

この場合、iOS7との互換性のために、次のように、「ぼかしビューを追加」コメントが配置される「if」条件を追加します。

if (NSClassFromString("UIVisualEffectView") != nil) {        
    // Add blur view
    let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light))
    blurView.frame = sideBarContainerView.bounds
    sideBarContainerView.addSubview(blurView)
}
9
Luismi

カスタムビューコントローラートランジションの使用は、スライドアウトメニューを作成するための堅実なアプローチだと思います。

  • アニメーションをカスタマイズできます。
  • トランジションはインタラクティブなので、ドラッグして前後に進めることができます。トランジションは常に終了またはロールバックし、ステート間でスタックすることはありません。
  • パンジェスチャとスクリーンエッジパンジェスチャを使用して、インタラクションを促進します。つまり、それらを戦略的に配置して、水平方向にジェスチャされたコンテンツとの競合を最小限に抑えることができます。
  • コンテナビューに頼る必要はありません。これは、アプリのアーキテクチャがよりフラットになり、NSNotificationsの代わりにprotocol-delegateを使用できることを意味します。
  • アクティブなViewControllerは一度に1つだけです。スナップショットは、画面に2番目のVCがあるという錯覚を与えるために使用されます。

interactive slide out animated GIF

カスタムView Controllerトランジションは、最初は習得が困難です(少なくとも私にとってはそうでした)。インタラクティブなスライドアウトメニューの作成方法について ブログ投稿 を作成し、できる限り簡単に理解できるように最善を尽くしました。

GitHubのコード に直接ジャンプすることもできます。

非常に高いレベルで、これはどのように機能するかです:

  1. モーダルとしてスライドアウトメニューを開きます。
  2. 現在のカスタムアニメーションを作成し、UIViewControllerAnimatedTransitioningプロトコルを使用してトランジションを閉じます。スナップショットを使用して、アニメーション中にメインビューコントローラーを表します。
  3. パンジェスチャレコグナイザーを作成して、モーダルをインタラクティブに表示/非表示にします。
  4. パンジェスチャイベントをUIPercentDrivenInteractiveTransitionオブジェクトに配線して、遷移をユーザーの動きと同期させます。
  5. 提示コントローラーはUIViewControllerTransitioningDelegateプロトコルを採用し、すべてのカスタムアニメーションとインタラクティブなトランジションを結び付けます。

実際、Scrollview/Container Viewを使用するこのスレッドに関する以前の回答があります。このアプローチはプロトタイプとしては問題ありませんが、アプリのプロダクションを準備する際に多くのEdgeのケースとバグに遭遇します。毎週ブログのコメントに返信し、Edgeのケースを修正することが、このテーマに関する2番目のブログ投稿を書くきっかけになりました。

8
Robert Chen

ここに、ミックスに追加するために作成した別のSideMenuライブラリを示します。 https://github.com/jonkykong/SideMen

Swift Facebookに触発されたiOSのシンプルなサイドメニューコントロール。右側と左側。コーディングは不要。

  • 1行のコードなしでストーリーボードに実装できます。
  • 4つの標準アニメーションスタイルから選択できます(奇妙な場合は視差も)。
  • 大量のカスタムコードを記述することなく高度にカスタマイズ可能。
  • 1回のジェスチャーで、両側のサイドメニュー間で連続スワイプをサポートします。
  • グローバルメニュー構成。一度セットアップすれば、すべての画面で完了します。
  • このコントロールはカスタムトランジションを使用するため、メニューは他のView Controllerと同じように表示および非表示にできます。

6
jonkykong

ここに私がそれを行う方法の小さな例を示します。この引き出しコントロールには、左、中央、右のuiviewcontrollersがあります。これは、どちらか一方が開いているSlack IPadアプリのように機能します。

/*
 To use simply instantiate SlidingDrawerController as your root view in your AppDelegate, or in the
 StoryBoard.
 Once SlidingDrawerController is instantiated, set the drawerSize of the SlidingDrawerController,
 and its leftViewControllerIdentifier, centerViewControllerIdentifier, and
 rightViewControllerIdentifier to the Storyboard Identifier of the UIViewController
 you want in the different locations.
 */

class SlidingDrawerController: UIViewController {
    var drawerSize:CGFloat = 4.0
    var leftViewControllerIdentifier:String = "leftViewController"
    var centerViewControllerIdentifier:String = "centerViewController"
    var rightViewControllerIdentifier:String = "rightViewController"

    enum Drawers {
        case left
        case right
    }

    private var _leftViewController:UIViewController?
    var leftViewController:UIViewController {
        get{
            if let vc = _leftViewController {
                return vc;
            }
            return UIViewController();
        }
    }
    private var _centerViewController:UIViewController?
    var centerViewController:UIViewController {
        get{
            if let vc = _centerViewController {
                return vc;
            }
            return UIViewController();
        }
    }
    private var _rightViewController:UIViewController?
    var rightViewController:UIViewController {
        get{
            if let vc = _rightViewController {
                return vc;
            }
            return UIViewController();
        }
    }

    static let SlidingDrawerOpenLeft = 1
    static let SlidingDrawerOpenRight = 2
    var openSide:SlidingDrawerController.Drawers {
        get{
            return _openSide;
        }
    }
    private var _openSide = SlidingDrawerController.Drawers.left

    override func viewDidLoad() {
        super.viewDidLoad()

        // Instantiate VC's with storyboard ID's
        self._leftViewController = self.instantiateViewControllers(storyboardID: self.leftViewControllerIdentifier)
        self._centerViewController = self.instantiateViewControllers(storyboardID: self.centerViewControllerIdentifier)
        self._rightViewController = self.instantiateViewControllers(storyboardID: self.rightViewControllerIdentifier)

        self.drawDrawers(size: UIScreen.main.bounds.size)

        self.view.addSubview(self.leftViewController.view)
        self.view.addSubview(self.centerViewController.view)
        self.view.addSubview(self.rightViewController.view)
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        coordinator.animateAlongsideTransition(in: self.view, animation: { (UIViewControllerTransitionCoordinatorContext) -> Void in
            // This is for beginning of transition
            self.drawDrawers(size: size)
        }, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
            // This is for after transition has completed.
        })

    }

    // MARK: - Drawing View

    func drawDrawers(size:CGSize) {
        // Calculate Center View's Size
        let centerWidth = (size.width/drawerSize) * (drawerSize - 1)
        // Left Drawer
        self.leftViewController.view.frame = CGRect(x: 0.0, y: 0.0, width: size.width/self.drawerSize, height: size.height)

        // Center Drawer
        self.centerViewController.view.frame = CGRect(x: self.leftViewController.view.frame.width, y: 0.0, width: centerWidth, height: size.height)

        // Right Drawer
        self.rightViewController.view.frame = CGRect(x: self.centerViewController.view.frame.Origin.x + self.centerViewController.view.frame.size.width, y: 0.0, width: size.width/self.drawerSize, height: size.height)

        // Capture the Swipes
        let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeRightAction(rec:)))
        swipeRight.direction = .right
        centerViewController.view.addGestureRecognizer(swipeRight)

        let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeLeftAction(rec:)))
        swipeLeft.direction = .left
        centerViewController.view.addGestureRecognizer(swipeLeft)

        openDrawer(openSide)
    }

    // MARK: - Open Drawers
    func openDrawer(_ side:Drawers) {
        self._openSide = side
        var rect:CGRect
        switch side{
        case .left:
            rect = CGRect(
                x: 0.0,
                y: 0.0,
                width: self.view.bounds.width,
                height: self.view.bounds.height
            )
        case .right:
            rect = CGRect(
                x: self.view.bounds.Origin.x - self.leftViewController.view.bounds.size.width,
                y: 0.0,
                width: self.view.bounds.width,
                height: self.view.bounds.height
            )
        }
        UIView.animate(withDuration: 0.1, delay: 0, options: UIViewAnimationOptions.curveEaseIn, animations:
            { () -> Void in
                // move views here
                self.view.frame = rect
        }, completion:
            { finished in
        })
    }

    // MARK: - Swipe Handling

    @objc func swipeRightAction(rec: UISwipeGestureRecognizer){
        self.openDrawer(.left)
    }

    @objc func swipeLeftAction(rec:UISwipeGestureRecognizer){
        self.openDrawer(.right)
    }

    // MARK: - Helpers

    func instantiateViewControllers(storyboardID: String) -> UIViewController {
        return UIStoryboard(name: "Main", bundle: nil)
                .instantiateViewController(withIdentifier: "\(storyboardID)")

    }
}

ソース ここ

画像 ここ

ビデオ ここ

5
Popmedic

2つの方法で実装しました。
最初はScroll Viewを使用し、2番目はContainer Viewsを使用します。

1つのコンテナでTableViewControllerをメニューとして機能させ、2番目のコンテナでTabBarControllerを非表示のタブで使用できます。テーブルビューでCellを押すと、タブバーのn番目のタブに移動します。

あなたがしなければならないのは、ボタンのクリックまたはジェスチャで一番上のコンテナをアニメーション化することです。その場合、次のようになります。

enter image description here

素敵なのは、組み込みのメソッドを使用してスプリングダンピングを使用してUIViewをアニメーション化するなどのクールな効果を簡単に追加して、リアルな弾むような効果を与えることができることです。メインビュー(写真には追加されていません)に影を追加して、メニューの上のページのように見せることもできます。

3
Fengson