Swift - 使用 UITableViewController 创建子菜单

Posted

技术标签:

【中文标题】Swift - 使用 UITableViewController 创建子菜单【英文标题】:Swift - Using UITableViewController to create sub-menus 【发布时间】:2016-08-04 08:50:41 【问题描述】:

我正在使用 Xcode 7 和 Swift 2 开发一个简单的混合 ios 应用程序。我需要从我的主菜单创建子菜单。

我的主菜单使用表格视图。现在我可以创建第二个UITableViewController 并在其中加载子菜单,然后创建第三个UITableViewController 以加载另一个子菜单,依此类推。

但是有没有更好的方法来重用我最初的UITableViewController

UITableViewController 嵌入在 UINavigationController 中。

我使用单个UIViewController 来显示最终的文本信息。

这是我的主菜单代码:

类 MainMenuTableViewController: UITableViewController

// MARK: Properties

var mainMenu = [MainMenu]()
var Item1Menu = [MainMenu]()
var Item12Menu = [MainMenu]()
var selectedMenu: Int = 0

override func viewDidLoad() 
    super.viewDidLoad()

    // Load the sample data.
    loadMainMenu()
    loadItem1Menu()
    loadItem12Menu()



func loadMainMenu() 
    let image1 = UIImage(named: "menu-1")!
    let menuItem1 = MainMenu(name: "Item 1", photo: image1, url: "no-url", urlType: "subMenu")!

    let image2 = UIImage(named: "menu-2")!
    let menuItem2 = MainMenu(name: "Item 2", photo: image2, url: "our-services", urlType: "localURL")!

    let image3 = UIImage(named: "menu-3")!
    let menuItem3 = MainMenu(name: "Item 3", photo: image3, url: "http://www.google.com", urlType: "webURL")!

    let image4 = UIImage(named: "menu-1")!
    let menuItem4 = MainMenu(name: "Item 4", photo: image4, url: "our-info", urlType: "localURL")!

    let image5 = UIImage(named: "menu-2")!
    let menuItem5 = MainMenu(name: "Item 5", photo: image5, url: "http://www.bing.com", urlType: "webURL")!

    //mainMenu.removeAll()
    mainMenu += [menuItem1, menuItem2, menuItem3, menuItem4, menuItem5]


func loadItem1Menu() 
    let image = UIImage(named: "menu-1")!
    let menuItem1 = MainMenu(name: "Item 1.1", photo: image, url: "our-profile", urlType: "localURL")!

    let menuItem2 = MainMenu(name: "Item 1.2", photo: image, url: "no-url", urlType: "sub-menu")!

    let menuItem3 = MainMenu(name: "Item 1.3", photo: image, url: "our-history", urlType: "localURL")!

    //mainMenu.removeAll()
    Item1Menu += [menuItem1, menuItem2, menuItem3]


func loadItem12Menu() 
    let image = UIImage(named: "menu-1")!
    let menuItem1 = MainMenu(name: "Item 1.2.1", photo: image, url: "portfolio-1", urlType: "localURL")!

    let menuItem2 = MainMenu(name: "Item 1.2.2", photo: image, url: "portfolio-2", urlType: "localURL")!

    let menuItem3 = MainMenu(name: "Item 1.2.3", photo: image, url: "portfolio-3", urlType: "localURL")!

    //mainMenu.removeAll()
    Item12Menu += [menuItem1, menuItem2, menuItem3]



override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int 
    return 1


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return mainMenu.count



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    // Table view cells are reused and should be dequeued using a cell identifier.
    let cellIdentifier = "MainMenuTableViewCell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! MainMenuTableViewCell

    // Fetches the appropriate menu for the data source layout.
    let menu = mainMenu[indexPath.row]

    cell.nameLabel.text = menu.name
    cell.menuImageView.image = menu.photo

    return cell


override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 

    var segueString:String
    selectedMenu = indexPath.row
    let urlType = mainMenu[selectedMenu].urlType

    if urlType == "subMenu" 

        //http://***.com/a/38763630/1019454
        let vc = (UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())).instantiateViewControllerWithIdentifier("MenuViewController") as! MainMenuTableViewController

        vc.mainMenu = Item1Menu
        // then push or present view controller
        self.navigationController!.pushViewController(vc, animated: true)

     else 


        switch(mainMenu[selectedMenu].urlType)

        case "localURL":
            segueString = "ShowLocalWeb"
        default:
            segueString = "ShowWeb"
        

        self.performSegueWithIdentifier(segueString, sender: self)
    



// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

    /*
    if segue.identifier == "ShowSubMenu" 
        let subMenuController = segue.destinationViewController as! SubMenuTableViewController
        subMenuController.subMenu = mainMenu[selectedMenu]
    */

    if segue.identifier == "ShowLocalWeb" 
        let localViewController = segue.destinationViewController as! LocalWebViewController
        localViewController.mainMenu = mainMenu[selectedMenu]
    

    if segue.identifier == "ShowWeb" 
        let webViewController = segue.destinationViewController as! WebViewController
        webViewController.mainMenu = mainMenu[selectedMenu]

    

【问题讨论】:

您可以使用相同的UITableViewController 来显示您的菜单。您只需要动态维护您的数据。您能否专门针对delegatedataSource 以及您使用/显示数据的方式展示您的代码? 我已经用代码更新了我的问题。 其实你们都准备好了。您需要的唯一更改是创建MainMenuTableViewController 的实例并为您的新菜单分配mainMenu 我真的是iOS新手,你能帮我一个sn-p实例化以及如何分配吗?我应该在哪里创建它? 请看答案。希望对你有帮助 【参考方案1】:

其实你们都准备好了。您需要的唯一更改是创建MainMenuTableViewController 的实例并将mainMenu 分配给您的新菜单。

例子:

当您希望显示新菜单时。

let vc = MainMenuTableViewController()
vc.menu = <new menu here>
// then push or present view controller
self.navigationController.pushViewController(vc, animated: true)

对以下评论的回应:

不,您不必创建新文件,而是创建 MainMenuTableViewController 的新实例。您必须更改数据部分,在您的案例数组中包含menu&lt;new menu here&gt; 指的是新菜单项的数组。

为此,您必须Decouple 数据,这将很有帮助。

编辑:

您可以尝试从情节提要中创建vc,而不是以上述方式创建您的vc。请按照以下步骤操作:

    在情节提要中将情节提要标识符分配给MainMenuTableViewController,而不是这一行

let vc = MainMenuTableViewController()

使用

let vc = (UIStoryboard(name: <your storyboard file name>, bundle: NSBundle.mainBundle())).instantiateViewControllerWithIdentifier(<storyboard identifier of MainMainMenuTableViewController>)

我怀疑的原因是我以前无法找到要创建的单元格并因此出现问题的行。

【讨论】:

这里的新菜单是什么意思?什么是 secondViewController?我必须创建一个新文件吗?如果是这样,那么就达不到目的了,因为我不想为每个新的向下钻取级别创建一个新的 TableViewController。 谢谢。我已经创建了一个新数组和所有内容。但我仍然不遵循 secondViewController 是什么,因此我的第一条评论。 MainMenuTableViewController.swift:106:59:使用未解析的标识符“secondViewController” 哦,对不起,我没有意识到它的 vc 而不是 secondViewController。已更正。 非常感谢,现在没有错误了。但我是 Swift 新手,所以需要弄清楚新实例是如何工作的并使用我加载的新数组。一旦我弄清楚了,我会发布更多帮助。现在我已经在 3 个答案中选择了你的方法。 我更新了上面问题中的代码。但是当我尝试单击具有子菜单的菜单时,它一直在崩溃。 Assertion failure in -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:]【参考方案2】:

如果我对问题的理解是正确的,我猜您有一个主菜单并希望在其下方显示子菜单。

一种方法是插入和删除行。这样你就可以重用相同的 UITableViewController。因此,在单击第 2 项时,可以将一组行插入到 tableView 中,该索引处填充有您的子菜单数据。

您可以在调用 tableView.beginUpdates() 和 tableView.endUpdates() 的块内使用函数 insertRowsAtIndexPaths(:withRowAnimation:) 和 deleteRowsAtIndexPaths(:withRowAnimation:) 并更新 tableView 数据源实现这一目标。

希望这会有所帮助。

【讨论】:

这似乎是我可以尝试的。虽然当我反击时会发生什么?它会自动处理,还是我必须记下我之前在哪个菜单并再次插入?我会试一试,看看它是如何工作的。我的主要目的是避免使用多个UITableViewController 它将自己处理。您只需要确保在删除和添加行时正确处理数据源。如果您需要有关代码部分的任何进一步帮助,请告诉我。 谢谢@anaghaajith27。但我发现 Vivek Molkar 的回答更容易,因为我只需要添加 3-4 行代码。创建一个实例实际上要容易得多,我只是不明白如何从情节提要中做到这一点。【参考方案3】:

如果您想要一个最简单的解决方案,您应该切换数据源并在 tableView 上调用 .reloadData()。

您是否实际上将拥有一些实现数据源协议的对象并在它们之间切换,或者将一组对象用作您的数据源并仅切换该数组的内容是您的决定,并且更多的是样式/架构方面的事情.

【讨论】:

我没有使用collectionView 所以我应该在我的viewDidLoad() 中使用.reloadData() 吗? 不,没有加载。在那里你可以设置第一个菜单。然后,当您选择一个单元格时,您会切换数据源并调用 reloadData。如果您想返回,那么您必须想出一个好方法,因为顶部的返回按钮不会为您执行此操作。这(以及将单元格作为子菜单插入 - 但这很困难)将允许您留在一个视图控制器中。 Vivek Molkar 所说的将起作用,但是它将创建一个新控制器并将其推送到具有动画过渡的导航堆栈上。 我不知道该怎么做,但我创建了一个新函数并调用了 reloadData() 但它似乎不起作用。我将不得不进一步阅读如何实现 reloadData。 loadSubMenu() tblView.reloadData() 它实际上工作并将行附加到主菜单,所以我没有注意到。我将不得不进一步阅读如何正确实现 reloadData。如果这工作正常且有效,我将更新帖子。 loadSubMenu() self.tblView.reloadData()我不知道 Vivek 的解决方案,所以我不知道它是如何工作的。

以上是关于Swift - 使用 UITableViewController 创建子菜单的主要内容,如果未能解决你的问题,请参考以下文章

如何将 UITableView 或 UITableViewController 集成到 UIPageViewController 中?

安全区域布局指南不适用于 UITableView 的 BackgroundView

如何从 Modal ViewController 重新加载父 UITableViewController 中的数据

如何让键盘在我的 UITableView 中与我的 UITextField 一起显示?

滚动视图加载内容的不同部分不一致? (iOS)

UITableView contentInset 使表格视图除了垂直滚动外还水平滚动