所以我想创建一个滑出菜单。我希望在触摸选项卡栏项目/按钮时菜单会滑出。 到目前为止,我已经创建了具有4个不同标签栏按钮的标签视图控制器。每个按钮都指向一个不同的视图控制器,并且每个视图控制器都被分隔到各自的情节提要中。
我尝试将侧面菜单的UIViewController添加到已经建立为UITabBarController的类中,但出现错误:
从类'UITabBarController'和'UIViewController'的多重继承。
有没有办法解决这个问题?
感谢所有帮助
答案 0 :(得分:2)
应用程序倾向于具有不能嵌入到View内部的顶级容器,例如Tab Bar Controller
。这里的方法是将主体和左侧菜单包装在Container View
中。现在,这两个元素都可以放在包装器View Controller
中。
Scroll View
用于通过在屏幕上/屏幕外移动左侧菜单来模拟打开和关闭菜单。
将View Controller
拖放到情节提要中。这是您进入应用程序的入口。
选中Is Initial View Controller
框。
将Simulated Size
从Fixed
更改为Freeform
。将“宽度”设置为568,以便我们可以并排放置菜单和选项卡栏。
创建一个新的Swift文件,并将该View Controller的类设置为ContainerVC。
import UIKit
class ContainerVC : UIViewController {
}
在Container View Controller内部,放入Scroll View
并在各个方向添加约束。
选中Scrolling Enabled
框。这使您可以平移屏幕以滑动菜单。如果您的应用程序使用水平滚动元素,则可能需要禁用此功能。
选中Paging Enabled
框。这会将菜单锁定为打开或关闭状态。
取消选中Bounces
的复选框。您真的不想滚动到标签栏控制器的右边缘。
将IBOutlet连接到ContainerVC:
@IBOutlet weak var scrollView: UIScrollView!
左边的容器保存菜单,并且不完全是屏幕的整个宽度。
将Container View
拖到Scroll View
的左侧。
在包含Scroll View
的顶部,左侧和右侧添加约束。
将宽度硬编码为260。
使用ContainerVC的嵌入式视图为Equal height
添加约束。注意:请勿将高度限制在“滚动视图”中。
删除View Controller
随附的嵌入式Container View
。
将新的Table View Controller
(根据您的需要按任何视图)拖放到情节提要中,然后使用嵌入的segue进行连接。
正确的容器包含应用程序的主体,即Tab Bar Controller
。
将第二个Container View
拖到Scroll View
的右侧。
将约束添加到包含Scroll View
的顶部,右侧和底部。水平连接到先前创建的左侧“容器视图”。
将Equal height
和Equal width
都约束到ContainerVC的嵌入式视图。
注意:请勿将其限制在“滚动视图”中。
同样,删除Container View
附带的嵌入式View Controller。相反,请为embed
创建一个Tab Bar Controller
序列。
要在两个容器之间创建一些视觉上的分隔,请在“正确的容器”中添加一个Runtime Attribute
。添加layer.shadowOpacity
和多个0.8
。
将每个标签嵌入Navigation Controller
中。这样可以为您提供免费的Navigation Bar
。
将Bar Button Item
拖到每个Navigation Bar
的左上角。
将IBAction
连接到每个控制器。这些将触发Notification
向曾祖父ContainerVC
切换菜单。
@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
}
}
该代码完成以下操作:
希望您有一个简单的左侧滑动菜单,可以在其上构建应用程序的其余部分。
答案 1 :(得分:0)
请勿使用UITabBarController,而应使用一个视图控制器和按钮操作来管理选项卡控件。
答案 2 :(得分:0)