SwiftUI如何实现点击按钮后展示对应下一级选项按钮
SwiftUI 实现长链式层级选择按钮交互
要实现点击按钮切换下一级选项组的链式选择流程,不需要硬编码多套页面和跳转逻辑,用树形数据结构+状态驱动动态渲染按钮即可,后续扩展任意层级的选项只需要修改数据配置,不用重复写布局代码。
核心实现逻辑
- 定义嵌套的选项数据结构,每个选项节点保存自身显示文本、以及下一级对应的子选项列表,天然匹配长链式选择的层级关系
- 用
@State追踪当前需要渲染的选项列表,初始值为最顶层的「Countries」「States」两个按钮 - 把原来硬编码写死的两个
NavigationLink改成动态遍历当前选项数组生成,点击按钮时判断该选项是否有子选项:有子选项就把当前渲染列表替换成该选项的子选项列表,自动刷新出新的按钮组;没有子选项就代表走到选择链末端,跳转到对应业务页面即可 - 可选增加返回上一级按钮,支持选择错误时回退
完整实现代码
import SwiftUI // 选项节点数据结构,支持无限层级嵌套 struct OptionNode: Identifiable { let id = UUID() let title: String var children: [OptionNode]? = nil } struct ContentView: View { @StateObject var triviaManager = TriviaManager() // 追踪当前需要展示的选项组 @State private var currentOptions: [OptionNode] // 追踪选择路径,用于返回上一级 @State private var selectionPath: [[OptionNode]] = [] // 初始化时配置整个链式选择的所有层级数据 init() { // 最顶层选项 let rootOptions = [ OptionNode(title: "Countries", children: [ OptionNode(title: "America", children: []), OptionNode(title: "Canada", children: []) ]), OptionNode(title: "States", children: [ OptionNode(title: "California", children: []), OptionNode(title: "Nevada", children: []) ]) ] _currentOptions = State(initialValue: rootOptions) } var body: some View { NavigationView { VStack(spacing: 40) { VStack(spacing: 20) { Text("Foodie's Pick") .lilacTitle() Text("Let's Find your Match") .foregroundColor(Color("AccentColor")) } // 动态渲染当前层级的所有按钮 HStack(spacing: 20) { ForEach(currentOptions) { option in NavigationLink { // 有子选项就切换下一级选项,没有子选项就跳转到题目页 if option.children != nil { Color.clear .onAppear { selectionPath.append(currentOptions) currentOptions = option.children ?? [] } } else { TriviaView() .environmentObject(triviaManager) } } label: { PrimaryButton(text: option.title) } } } // 非顶层时显示返回上一级按钮 if !selectionPath.isEmpty { Button("返回上一级") { currentOptions = selectionPath.removeLast() } .foregroundColor(.gray) } } .frame(maxWidth: .infinity, maxHeight: .infinity) .edgesIgnoringSafeArea(.all) .background(Color(red: 1, green: 1, blue: 1)) .navigationViewStyle(.stack) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
扩展说明
如果后续要加长选择链路,只需要在init里的对应节点下增加children数组内容即可,比如要给「California」下加「Los Angeles」「San Francisco」两个选项,直接修改对应节点:
OptionNode(title: "California", children: [ OptionNode(title: "Los Angeles"), OptionNode(title: "San Francisco") ])
不需要修改任何布局和跳转逻辑,页面会自动渲染新层级的按钮组。
内容的提问来源于stack exchange,提问作者Swifty
相关产品推荐
相关产品推荐

