如何在swift中从树数据结构制作UIButtons

时间:2017-05-10 16:16:48

标签: ios swift

我有一个树数据结构,并希望使用该树结构来生成按钮,这些按钮使用新的视图控制器以编程方式分割给它的子项,就像在Apple的设置菜单中,您有不同的选项,当您点击随机父项时它会贬低它的孩子。

    class OptionNode{
    var value: String

    weak var parent: OptionNode?
    var children = [OptionNode]()

    init(value: String){
        self.value = value
    }

    func addOption(node: OptionNode){
        children.append(node)
        node.parent = self
    }
}

struct MenuStructure {

static var menuOptions: OptionNode {

    let mainMenu = OptionNode(value: "Main Menu")
    let vehicle = OptionNode(value: "vehicle Menu")
    let food = OptionNode(value: "Food Menu")
    let computer = OptionNode(value: "Computer Menu")

    let ford = OptionNode(value: "Ford Menu")
    let toyota = OptionNode(value: "Toyota Menu")
    let honda = OptionNode(value: "Honda Menu")

    let apple = OptionNode(value: "Apple Menu")
    let orange = OptionNode(value: "Orange Menu")
    let pear = OptionNode(value: "Pear Menu")

    let hp = OptionNode(value: "HP Menu")
    let chrome = OptionNode(value: "Chrome Menu")
    let samsung = OptionNode(value: "Samsung Menu")

    mainMenu.addOption(node: vehicle)
    mainMenu.addOption(node: food)
    mainMenu.addOption(node: computer)

    vehicle.addOption(node: ford)
    vehicle.addOption(node: toyota)
    vehicle.addOption(node: honda)

    food.addOption(node: apple)
    food.addOption(node: orange)
    food.addOption(node: pear)

    computer.addOption(node: hp)
    computer.addOption(node: chrome)
    computer.addOption(node: samsung)

    return mainMenu

    }
}

因此,代码的第一部分是建立我的树数据结构,其余代码是使用先前定义的节点填充我的树结构。这将与viewController分开,因为这是MVC的模型层。然后,使用该树结构,我想以编程方式添加表示树结构的按钮。因此,例如,第一页将有三个按钮,即“车辆”,“食物”和“计算机”,当用户点击“食物”按钮时,屏幕将通过另一组按钮切换到新的视图控制器,即“Apple”,“Orange”和“Pear”。希望这是有道理的,谢谢!

谢谢

1 个答案:

答案 0 :(得分:1)

好的,正如我所承诺的那样,我写了一个演示项目,希望能帮助您了解这是如何工作的。我只是简单地包含了您的演示数据,因此您可以更好地关注:https://github.com/GeroHerkenrath/SOExDynamicButtonGen

在这里提供SO的解释(并使其成为一个独立于我的演示的有用答案),一些一般性的东西:

如果我理解正确,那么想法是完全动态地确定要为给定节点显示的视图控制器。即单击一个按钮,然后确定的场景显示子项,如果单击它们,则会出现一个新场景,等等。

我说场景,因为这主要发生了什么,虽然重要的部分实际上是视图控制器。对于用户而言,两者都可见,例如在iPad上的主详细视图中(在iPhone上它基本上是两个单独显示的表视图控制器)。我之所以提到这一点,是因为您自己提到了“设置”应用,这基本上是主视图/详细信息视图。

现在就是这样:

由于您的UI基本上是在运行时确定的,因此我建议您不要使用场景和segues。我的示例项目显示了这一点,并有一些进一步的解释(我将在底部添加),为什么会这样。您可以将故事板基本上用作(例如"存储库")所需的视图控制器,然后通过标识符进行实例化。在我的示例中,我只使用表视图控制器(或者更确切地说,重复使用的控制器)和导航视图控制器来演示这一点。您的UI可能看起来不同,包含容器视图或所述主细节控制器。一旦你实例化了一个视图控制器,你可以用它做任何必要的事情(我把它推到导航堆栈上)。这可能变得复杂,但有无限的可能性,我无法为所有事情提供演示。 :)导航视图控制器是最简单的例子,但是经常遇到的一个,而iPhone很大程度上依赖它(由于屏幕尺寸)。

所以要把它形成为ToDos的公式:

  1. 为树中的节点类型创建视图控制器(取决于您的设计方式)。在故事板中为他们提供一个标识符,但不要将它们与segues连接。
  2. 在常规UI中准备导航视图控制器。从中获得树,实例化第一个视图控制器(顶层),使用根节点准备它并将其推入堆栈。
  3. 在这些控制器的代码中,使用节点的数据根据​​需要配置UI。依靠子节点填充表格单元格,按钮等。
  4. 再次在控制器中,在处理表示子项的元素(我的示例中的单元格)上的单击的部分中,根据需要实例化一个新的视图控制器,就像在导航控制器的开头一样。堆栈。用选定的子数据和子数据填充它。推动它。
  5. 如上所述,如果您不使用导航视图控制器,则必须执行您需要的任何其他操作(将其嵌入到容器视图或其他任何内容中),但我想在某处你会有这个。以模态方式显示控制器也可能是一个选项(即不是"推动导航堆栈",而是调用presentViewController或其他任何调用。)

    我希望这可以帮助你理解UI的复杂性,随意拉动我的github项目并在其中玩游戏。 另请阅读自述文件,我解释了我在那里做了什么。

    最后,我会在这里复制我的自述文章部分,我认为这对于所有人来说都是一个很有价值的提示,也适用于iOS新手:

      

    关于故事板设计的一般说明&关于场景转换的动态决策

         

    你可以用故事板做很多事情,甚至没有它们(我甚至没有在实例化视图控制器时使用普通的旧xib)。但是,这并不意味着你应该做所有事情。   就个人而言,我总是把它们的名字完全取名。我希望我的故事板能够在我查看它们时帮助理解程序的UI流程。   在我的故事板中,segue是尽可能自动的。   有一次我甚至添加了一个我没有用过的segue,只是为了说明从那里到那里的转换(开销很小,因为它只是故事板中的一个小条目,永远不会做任何事情)

         

    如果我想拥有"实用程序"我从代码中实例化的场景/视图控制器我很清楚(遗憾的是,我无法在故事板上添加评论,这将是neato IMO),例如我将它们分组,甚至可能使用不同的故事板,或者我去首先使用xib解决方案。

         

    重要的是要考虑整个项目的可读性,并且通过标识符和常规的segue过渡不经意地混合实例化可能导致混乱,并且难以追踪错误。   在此示例项目中,DynamicLevelController tableView(_:didSelectRowAt:)我提供了一个示例,说明了我认为不应该做的事情。

         

    我遇到过像这样的代码的项目,这直接导致故事板误导:   故事板看起来像是一个特定的路径,场景与单个"浮动"您可能一开始认为是一个可以从任何地方访问的实用程序。   这个实用程序控制器中的代码然后突然导致一个随机点,在最初看起来像一个常规,漂亮的场景路径。   要弄清楚这一点,你必须在代码中查看几个地方,比较标识符等等。那没用。

         

    如果您需要做这样的事情,可能会出现这种情况,但如果没有真正的需要,那么就不要这样做。