繁体   English   中英

如何将滑出/汉堡菜单合并到现有的标签栏控制器

[英]How do I incorporate a slide out/burger menu to an existing tab bar controller

所以我想创建一个滑出菜单。 我希望菜单在触摸选项卡栏项目/按钮时滑出。 到目前为止,我已经创建了一个带有 4 个不同选项卡栏按钮的选项卡视图控制器。 每个按钮通向不同的视图控制器,并且每个视图控制器都被分离到它们自己的故事板中。

我尝试将侧边菜单的 UIViewController 添加到已经建立为 UITabBarController 的类中,但出现错误:

从类“UITabBarController”和“UIViewController”的多重继承。

有没有解决的办法?

我感谢所有的帮助

应用程序往往有一个顶级容器,比如无法嵌入到视图中的Tab Bar Controller 这里的方法是将主体和左侧菜单分别包装在Container View 现在这两个元素都可以安排在包装器View Controller

容器故事板

Scroll View用于通过在屏幕上/屏幕外移动左侧菜单来模拟打开和关闭菜单。

包含视图控制器

View Controller拖放到情节提要上。 这是您进入应用程序的入口点。 选中Is Initial View Controller复选框。 Simulated SizeFixed更改为Freeform 将宽度设置为 568,这样我们就可以并排放置菜单和标签栏。 创建一个新的 Swift 文件并将此视图控制器的类设置为 ContainerVC。

import UIKit
class ContainerVC : UIViewController {
}

滚动视图

在 Container View Controller 中,放入一个Scroll View并在所有方向上添加约束。

选中Scrolling Enabled复选框。 这允许您平移屏幕以滑动菜单。 如果您的应用使用水平滚动元素,您可能需要禁用此功能。

选中Paging Enabled复选框。 这会将菜单捕捉到打开或关闭状态。

取消选中Bounces框。 您真的不想滚动超过 Tab Bar Controller 的右边缘。

将 IBOutlet 连接到 ContainerVC:

@IBOutlet weak var scrollView: UIScrollView!

左容器

左边的容器包含菜单,并不完全是屏幕的整个宽度。

Container View拖到Scroll View的左侧。

将顶部、左侧和右侧的约束添加到包含的Scroll View

将宽度硬编码为 260。

使用 ContainerVC 的嵌入视图为Equal height添加约束。 注意:不要限制滚动视图的高度。 删除Container View附带的嵌入式View Controller

将一个新的Table View Controller (根据您的需要的任何视图)放到故事板上,并使用嵌入转场进行连接。

正确的容器

正确的容器包含应用程序的主体,即Tab Bar Controller

将第二个Container View拖到Scroll View的右侧。

向包含Scroll View的顶部、右侧和底部添加约束。 水平连接到您之前创建的左侧容器视图。

Equal heightEqual width为 ContainerVC 的嵌入视图。

注意:不要将这些限制在滚动视图中。

setConstraintsFromContainers

再次,删除随Container View免费提供的嵌入式视图控制器。 相反,创建一个embedTab Bar Controller segue。

要在两个容器之间创建一点视觉分离,请将Runtime Attribute添加到右侧容器。 添加layer.shadowOpacity的数字为0.8

标签

将每个选项卡嵌入到Navigation Controller 这样做会为您提供一个免费的Navigation Bar

将一个Bar Button Item拖到每个Navigation Bar左上角。

IBAction到每个控制器。 这些将向曾祖父ContainerVC发出Notification以切换菜单。

@IBAction func toggleMenu(sender: AnyObject) {
  NotificationCenter.default().post(name: Notification.Name("toggleMenu"), object: nil)
}

最后将以下代码添加到 ContainerVC 中:

class ContainerVC : UIViewController {

    // This value matches the left menu's width in the Storyboard
    let leftMenuWidth:CGFloat = 260

    // Need a handle to the scrollView to open and close the menu
    @IBOutlet weak var scrollView: UIScrollView!

    override func viewDidLoad() {

        // Initially close menu programmatically.  This needs to be done on the main thread initially in order to work.
        DispatchQueue.main.async() {
            self.closeMenu(animated: false)
        }

        // Tab bar controller's child pages have a top-left button toggles the menu
        NotificationCenter.default.addObserver(self, selector: #selector(ContainerVC.toggleMenu), name: NSNotification.Name(rawValue: "toggleMenu"), object: nil)

        NotificationCenter.default.addObserver(self, selector: #selector(ContainerVC.closeMenuViaNotification), name: NSNotification.Name(rawValue: "closeMenuViaNotification"), object: nil)

        // Close the menu when the device rotates
        NotificationCenter.default.addObserver(self, selector: #selector(ContainerVC.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

        // LeftMenu sends openModalWindow
        NotificationCenter.default.addObserver(self, selector: #selector(ContainerVC.openModalWindow), name: NSNotification.Name(rawValue: "openModalWindow"), object: nil)

    }

    // Cleanup notifications added in viewDidLoad
    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    @objc func openModalWindow() {
        performSegue(withIdentifier: "openModalWindow", sender: nil)
    }

    @objc func toggleMenu() {
        scrollView.contentOffset.x == 0  ? closeMenu() : openMenu()
    }

    // This wrapper function is necessary because closeMenu params do not match up with Notification
    @objc func closeMenuViaNotification(){
        closeMenu()
    }

    // Use scrollview content offset-x to slide the menu.
    func closeMenu(animated:Bool = true){
        scrollView.setContentOffset(CGPoint(x: leftMenuWidth, y: 0), animated: animated)
    }

    // Open is the natural state of the menu because of how the storyboard is setup.
    func openMenu(){
        print("opening menu")
        scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
    }

    @objc func rotated(){
        if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
            DispatchQueue.main.async() {
                print("closing menu on rotate")
                self.closeMenu()
            }
        }
    }
}

extension ContainerVC : UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("scrollView.contentOffset.x:: \(scrollView.contentOffset.x)")
    }

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        scrollView.isPagingEnabled = true
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        scrollView.isPagingEnabled = false
    }
}

该代码实现了以下功能:

  • 监听“toggleMenu”通知
  • 通过基于当前的 contentOffset.x 打开或关闭来实现 toggleMenu 方法
  • 通过更改 contentOffset-x 打开和关闭菜单。

希望您有一个简单的滑出式左侧菜单,可以在其上构建应用程序的其余部分。

不要使用 UITabBarController,并使用一个视图控制器和按钮操作来管理选项卡控件。

@Ajo 答案是正确的。 在容器视图中嵌入汉堡包和标签栏。

您可以从下面的链接中找到完整的源代码

源代码链接

还有一个详细的教程我找到了教程链接

使用初始视图控制器作为容器视图。 使用滑入/滑出通知

故事板图像

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM