滑动边栏菜单IOS 8 Swift

时间:2014-06-09 14:57:51

标签: swift ios8

有没有办法在没有任何第三方库的IOS Swift中实现Slide Sidebar Menu(如Facebook应用程序)?我寻找解决方案但我只创建了在Objective-C中实现的这个功能。

7 个答案:

答案 0 :(得分:17)

我相信你可以从iOS8中大幅更新的UISplitViewController开始。有关详细信息,请观看会话View Controller Advancements in iOS8Building Adaptive Apps with UIKit。他们提供code example from second session(但不是第一个:/)。在这一点上,我很自然地在iOS8中基于分割视图控制器制作这种UI。

更新:看起来并非他们所谈论的所有API都已登陆。例如,在视频中提到的当前beta4中没有提供BarsOnSwipe,例如。

答案 1 :(得分:16)

  

更新:请考虑使用我更新的答案而不是此答案。通过使用自定义视图控制器转换可以避免使用Scrollview / Container View方法的许多边缘情况。

我到处寻找一个不需要图书馆的Swift菜单解决方案。结束创建我自己的教程,这与Fengson的方法非常相似:

enter image description here

以下是一些要点:

  • 创建一个scrollview,它将处理菜单滑动动作以及平移手势
  • container内并排放置两个scrollview视图。容器允许您嵌入顶级控制器。
  • scrollview上,设置paging enabled但禁用bounces。这将迫使滑道进入开放或关闭状态
  • embed左侧容器中的UITableViewController
  • embed右侧容器中的UITabBarController
  • 在右侧container,添加0.8的运行时属性layer.shadowOpacity。这为您提供了一个没有任何代码的免费阴影分隔符。
  • 添加菜单按钮。您可以使用NSNotificationCenterscrollview
  • 进行通信
  • 对于秘密成分:使用scrollView.setContentOffset.x来处理菜单的实际打开和关闭

这是一个标签栏应用程序的工作示例项目,带有左侧滑出菜单,包括屏幕截图和说明。

https://github.com/ThornTechPublic/LeftSlideoutMenu

除了对其工作方式的更一般性解释:

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

答案 2 :(得分:9)

滑动侧边栏菜单,适用于iOS7和iOS8,Swift编码。

如果你想要它在 NavigationController级别(这意味着,对于它背后的视图控制器):

https://github.com/evnaz/ENSwiftSideMenu

如果您只想在一个 ViewController

视频:https://www.youtube.com/watch?v=qaLiZgUK2T0

源代码:http://goo.gl/ULWxJh

在这种情况下,对于iOS7兼容性,只需添加此"如果"条件所在的"添加模糊视图"发表评论,如下:

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

答案 3 :(得分:8)

我认为使用自定义视图控制器转换是制作滑出菜单的可靠方法:

  • 您可以自定义动画。
  • 转换是交互式的,因此您可以拖动以前进和后退。转换总是完成或回滚,并且永远不会陷入中间状态。
  • 您可以使用Pan Gestures和Screen Edge Pan Gestures来推动互动。这意味着您可以策略性地放置它们以最小化与水平手势内容的冲突。
  • 您不必诉诸容器视图。这意味着您的应用程序架构更平坦,您可以使用protocol-delegate而不是NSNotifications。
  • 一次只有一个ViewController处于活动状态。快照用于表示屏幕上有第二个VC。

interactive slide out animated GIF

自定义视图控制器转换起初很难学习(至少对我来说是这样)。我写了一篇关于如何创建交互式幻灯片菜单的blog post,并尽力使其尽可能易于理解。

您也可以直接跳到code on GitHub

在很高的层面上,这就是它的工作原理:

  1. 您可以将幻灯片菜单作为模式打开。
  2. 您可以使用UIViewControllerAnimatedTransitioning协议为当前创建自定义动画并关闭过渡。您可以使用快照在动画期间表示主视图控制器。
  3. 您可以创建Pan Gesture Recognizers以交互方式呈现/取消模态。
  4. 您将Pan Gesture事件连接到UIPercentDrivenInteractiveTransition对象,以使转换与用户的动作保持同步。
  5. 演示控制器采用UIViewControllerTransitioningDelegate协议并连接所有自定义动画和交互式过渡。
  6. 我实际上在此线程上有一个使用Scrollview / Container View的先前答案。这种方法适用于原型,但在准备好应用程序生产时会遇到很多边缘情况和错误。每周花在回应博客评论和修复边缘案例上的动机促使我写了关于这个主题的第二篇博文。

答案 4 :(得分:6)

这是我添加到混音中的另一个SideMenu库:https://github.com/jonkykong/SideMenu

  

受Facebook欢迎的Swift iOS简单侧边菜单控制。对   和左侧。无需编码。

     
      
  • 可以在没有单行代码的情况下在故事板中实现。
  •   
  • 四种标准动画风格可供选择(如果你想变得奇怪,甚至是视差)。
  •   
  • 高度可定制,无需编写大量自定义代码。
  •   
  • 支持在一个手势中连续滑动两侧的侧面菜单。
  •   
  • 全局菜单配置。设置一次并完成所有屏幕。
  •   
  • 菜单可以与任何其他View Controller一样显示和解除,因为此控件使用自定义转换。
  •   
     

答案 5 :(得分:5)

这是我如何做的一个小例子,这个抽屉控件有左,中,右的uiview控制器。这个工作就像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)")

    }
}

来源here

图片here

视频here

答案 6 :(得分:3)

我已经用两种方式实现了它 首先使用Scroll View,然后使用Container Views

您可以在一个容器中将TableViewController作为菜单,在第二个容器中使用隐藏标签TabBarController。在表格视图中按Cell可移动到标签栏中的第n个选项卡。

您只需在按钮单击或手势上为顶部容器设置动画。它可能看起来像这样:

enter image description here

什么是巧妙的是你可以轻松添加很酷的效果,比如使用弹簧阻尼动画UIView,使用内置方法来赋予其逼真的弹性效果。您还可以在主视图中添加阴影(未添加到图片中),使其看起来像菜单上方的页面。