SwiftUI 动态生成按钮场景下跨视图参数传递与选中状态设置问题
问题原因及解决方案
1. 为什么onAppear会输出2轮共6条日志
核心原因有两个:
- 你使用的
NavigationLink的destination参数是即时求值的,不是懒加载:Landing页首次渲染时tag为nil,会先生成一次ContentView(landingChoice: ""),触发一次ForEach三个元素的onAppear打印;点击按钮修改tag值后,会再次生成对应选中值的ContentView,触发第二次打印,加起来就是6条日志。 - 当前使用的
ForEach(0..<buttonEnvObj.buttonNames.count)是基于范围的无ID标识遍历,SwiftUI视图重绘时不会复用元素标识,也会增加额外的渲染触发概率,优化可改成直接遍历字符串数组的写法,更稳定。
2. 为什么传入参数后按钮不会自动选中
你在ContentView的初始化方法里只是把传入的landingChoice存到了btnName属性,完全没有调用状态修改方法更新按钮的选中状态,自然不会自动触发选中。
修复代码
第一步:修复ContentView自动选中逻辑
给ContentView添加onAppear修饰符,进入页面时主动调用状态更新方法,同时优化ForEach写法:
struct ContentView: View { var btnName:String @EnvironmentObject var buttonEnvObj:ButtonOnOff init(landingChoice:String){ self.btnName = landingChoice print("\(self.btnName) is the input string") } var body: some View { VStack{ Form{ Section{ ScrollView(.horizontal, showsIndicators: false) { HStack(spacing:10) { // 优化ForEach写法,直接遍历字符串数组 ForEach(buttonEnvObj.buttonNames, id: \.self) { name in BubbleButton(label: name) .padding(EdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 0)) .onAppear { print("\(name) is the title") } } } }.frame(height: 50) } } } // 新增:进入页面时自动选中传入的按钮 .onAppear { guard !btnName.isEmpty else { return } buttonEnvObj.changeState(buttonName: btnName) } } }
第二步:可选优化,修复NavigationLink重复初始化问题
如果要避免ContentView重复初始化,可把NavigationLink的destination改成懒加载闭包形式(SwiftUI 3+支持),只有跳转时才会创建ContentView,就不会出现两次打印的情况。修改Landing.swift里的NavigationLink代码:
NavigationLink(destination: { ContentView(landingChoice:tag ?? "") }, tag: tag ?? "", selection: $tag) { EmptyView() }
内容的提问来源于stack exchange,提问作者ninu
相关产品推荐
相关产品推荐

