Ios 如何将滑出/汉堡菜单合并到现有的选项卡栏控制器
所以我想创建一个滑出菜单。我希望在触摸选项卡栏项目/按钮时,菜单滑出。 到目前为止,我已经创建了一个带有4个不同选项卡栏按钮的选项卡视图控制器。每个按钮都指向不同的视图控制器,每个视图控制器都已分离到各自的故事板中 我尝试将侧菜单的UIViewController添加到已建立为UIAbbarController的类中,但出现错误: 从类“UITabBarController”和“UIViewController”的多重继承 有办法解决这个问题吗Ios 如何将滑出/汉堡菜单合并到现有的选项卡栏控制器,ios,uitabbarcontroller,swift4,Ios,Uitabbarcontroller,Swift4,所以我想创建一个滑出菜单。我希望在触摸选项卡栏项目/按钮时,菜单滑出。 到目前为止,我已经创建了一个带有4个不同选项卡栏按钮的选项卡视图控制器。每个按钮都指向不同的视图控制器,每个视图控制器都已分离到各自的故事板中 我尝试将侧菜单的UIViewController添加到已建立为UIAbbarController的类中,但出现错误: 从类“UITabBarController”和“UIViewController”的多重继承 有办法解决这个问题吗 我感谢所有的帮助不要使用UITabBarContr
我感谢所有的帮助不要使用UITabBarController,使用一个视图控制器和按钮操作来管理选项卡控件。应用程序往往有一个顶级容器,如
选项卡栏控制器
,不能嵌入视图中。这里的方法是将主体和左菜单分别包装在容器视图中。现在,这两个元素都可以安排在包装器视图控制器中
一个滚动视图
用于通过移动左菜单开/关屏幕来模拟打开和关闭菜单
包含视图控制器
将视图控制器
放到情节提要上。这是您进入应用程序的入口点。
选中为初始视图控制器的复选框。
将模拟大小
从固定
更改为自由形式
。将宽度设置为568,以便我们可以并排安装菜单和选项卡栏。
创建新的Swift文件并将此视图控制器的类设置为ContainerVC
import UIKit
class ContainerVC : UIViewController {
}
滚动视图
在容器视图控制器内,放入一个滚动视图
,并在各个方向添加约束
选中启用滚动的框
。这允许您平移屏幕以滑动菜单。如果应用程序使用水平滚动元素,则可能需要禁用此功能
选中启用分页的框。这会将菜单捕捉到打开或关闭状态
取消选中反弹
框。您确实不想滚动到选项卡栏控制器的右边缘
将IB插座连接至ContainerVC:
@IBOutlet weak var scrollView: UIScrollView!
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
}
}
左容器
左边的容器保存着菜单,并不是整个屏幕的宽度
将容器视图
拖动到滚动视图的左侧
将顶部、左侧和右侧的约束添加到包含的滚动视图
硬编码宽度为260
使用ContainerVC的嵌入视图为等高添加约束。注意:不要将高度约束到滚动视图。
删除容器视图附带的嵌入式视图控制器
将一个新的表视图控制器
(根据需要的任何视图)放到情节提要上,并使用嵌入式segue进行连接
右容器
右边的容器包含应用程序的主体,即选项卡栏控制器
将第二个容器视图
拖动到滚动视图的右侧
向包含顶部、右侧和底部的滚动视图添加约束。水平连接到先前创建的左侧容器视图
将等高
和等宽
约束到ContainerVC的嵌入视图
注意:不要将这些限制到滚动视图
再次删除随容器视图免费提供的嵌入式视图控制器。相反,创建一个embed
segue到选项卡栏控制器
要在两个容器之间创建一个小的可视分隔,请在右侧容器中添加一个运行时属性
。添加layer.shadowOpacity
,数字为0.8
标签
将每个选项卡嵌入导航控制器
。这样做可以为您提供一个免费的导航栏
将栏按钮项
拖动到每个导航栏的左上角
将iAction
连接到每个控制器。它们将向曾祖父发出通知
,以切换菜单
@IBAction func toggleMenu(sender: AnyObject) {
NotificationCenter.default().post(name: Notification.Name("toggleMenu"), object: nil)
}
最后将以下代码添加到ContainerVC中:
@IBOutlet weak var scrollView: UIScrollView!
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
}
}
该代码实现以下功能:
- 收听“切换菜单”通知
- 通过基于
当前contentOffset.x
- 通过更改contentOffset-x打开和关闭菜单
希望您有一个简单的左滑出菜单,可以在其上构建应用程序的其余部分。@Ajo-answer是正确的。在容器视图中嵌入hamburger和tabbar
你可以从下面的链接找到完整的源代码
我还发现了一个详细的教程
将初始视图控制器用作容器视图。
使用滑入/滑出通知
请显示您的问题代码。PS:UIAbbarController已经从UIViewController继承。我使用故事板而不是代码创建了选项卡栏,这可能不是一个好主意,所以我应该放弃UIAbbarController,使用视图控制器以编程方式创建选项卡栏?