我有一个树数据结构,并希望使用该树结构来生成按钮,这些按钮使用新的视图控制器以编程方式分割给它的子项,就像在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”。希望这是有道理的,谢谢!
谢谢
答案 0 :(得分:1)
好的,正如我所承诺的那样,我写了一个演示项目,希望能帮助您了解这是如何工作的。我只是简单地包含了您的演示数据,因此您可以更好地关注:https://github.com/GeroHerkenrath/SOExDynamicButtonGen
在这里提供SO的解释(并使其成为一个独立于我的演示的有用答案),一些一般性的东西:
如果我理解正确,那么想法是完全动态地确定要为给定节点显示的视图控制器。即单击一个按钮,然后确定的场景显示子项,如果单击它们,则会出现一个新场景,等等。
我说场景,因为这主要发生了什么,虽然重要的部分实际上是视图控制器。对于用户而言,两者都可见,例如在iPad上的主详细视图中(在iPhone上它基本上是两个单独显示的表视图控制器)。我之所以提到这一点,是因为您自己提到了“设置”应用,这基本上是主视图/详细信息视图。
现在就是这样:
由于您的UI基本上是在运行时确定的,因此我建议您不要使用场景和segues。我的示例项目显示了这一点,并有一些进一步的解释(我将在底部添加),为什么会这样。您可以将故事板基本上用作(例如"存储库")所需的视图控制器,然后通过标识符进行实例化。在我的示例中,我只使用表视图控制器(或者更确切地说,重复使用的控制器)和导航视图控制器来演示这一点。您的UI可能看起来不同,包含容器视图或所述主细节控制器。一旦你实例化了一个视图控制器,你可以用它做任何必要的事情(我把它推到导航堆栈上)。这可能变得复杂,但有无限的可能性,我无法为所有事情提供演示。 :)导航视图控制器是最简单的例子,但是经常遇到的一个,而iPhone很大程度上依赖它(由于屏幕尺寸)。
所以要把它形成为ToDos的公式:
如上所述,如果您不使用导航视图控制器,则必须执行您需要的任何其他操作(将其嵌入到容器视图或其他任何内容中),但我想在某处你会有这个。以模态方式显示控制器也可能是一个选项(即不是"推动导航堆栈",而是调用presentViewController
或其他任何调用。)
我希望这可以帮助你理解UI的复杂性,随意拉动我的github项目并在其中玩游戏。 另请阅读自述文件,我解释了我在那里做了什么。
最后,我会在这里复制我的自述文章部分,我认为这对于所有人来说都是一个很有价值的提示,也适用于iOS新手:
关于故事板设计的一般说明&关于场景转换的动态决策
你可以用故事板做很多事情,甚至没有它们(我甚至没有在实例化视图控制器时使用普通的旧xib)。但是,这并不意味着你应该做所有事情。 就个人而言,我总是把它们的名字完全取名。我希望我的故事板能够在我查看它们时帮助理解程序的UI流程。 在我的故事板中,segue是尽可能自动的。 有一次我甚至添加了一个我没有用过的segue,只是为了说明从那里到那里的转换(开销很小,因为它只是故事板中的一个小条目,永远不会做任何事情)
如果我想拥有"实用程序"我从代码中实例化的场景/视图控制器我很清楚(遗憾的是,我无法在故事板上添加评论,这将是neato IMO),例如我将它们分组,甚至可能使用不同的故事板,或者我去首先使用xib解决方案。
重要的是要考虑整个项目的可读性,并且通过标识符和常规的segue过渡不经意地混合实例化可能导致混乱,并且难以追踪错误。 在此示例项目中,
DynamicLevelController
tableView(_:didSelectRowAt:)
我提供了一个示例,说明了我认为不应该做的事情。我遇到过像这样的代码的项目,这直接导致故事板误导: 故事板看起来像是一个特定的路径,场景与单个"浮动"您可能一开始认为是一个可以从任何地方访问的实用程序。 这个实用程序控制器中的代码然后突然导致一个随机点,在最初看起来像一个常规,漂亮的场景路径。 要弄清楚这一点,你必须在代码中查看几个地方,比较标识符等等。那没用。
如果您需要做这样的事情,可能会出现这种情况,但如果没有真正的需要,那么就不要这样做。