SwiftUI中如何自定义类似TabView的选择性显示子视图组件?
注:若多年后看到此问题的用户请注意: 当前正确解决方案为“使用iOS 18新增的Group(subviews:transform:)”,它能提供所需的精准功能,且API简洁易用。
下方的VariadicView方案较为复杂,现已无需使用;仅具有历史参考价值。
自定义类似TabView的子视图切换组件
TabView的content体可包含多个子视图,且同一时间仅显示其中一个。我希望自定义一个视图,能通过ViewBuilder接收异构内容,实现类似功能:选择性显示指定的子视图,隐藏其余视图。
该视图需类似TabView的子视图管理逻辑,但由我通过代码控制,且不具备TabView的其他额外行为。它应能接收任意类型混合的内容项,例如ForEach输出、Group元素等,完全和TabView一致。
当前效果:
但我希望仅显示这三个子视图中的一个(由我指定)。
以下是我期望能运行的代码,目标清晰明了……
import SwiftUI struct SwitcherView<Content>: View where Content: View { let content: () -> Content @State var selection: Int = 0 // 未展示修改该值的逻辑 public init(@ViewBuilder content: @escaping () -> Content) { self.content = content } @MainActor public var body: some View { VStack { content()[selection] // 显然此代码无法运行 } } } struct SwitcherView_Previews: PreviewProvider { static var previews: some View { VStack { Text("I would like to show just one of these at a time:") SwitcherView { // 注意异构内容:每个元素都有独立的类型和状态, // SwitcherView无需显式知晓这些信息,就像TabView一样! Text("First Content") .frame(width: 100, height: 100) .background(.red) Button(action: {}, label: { Text("I'm a yellow button!") }) .buttonStyle(.borderedProminent) .tint(.green) .frame(width: 100, height: 100) HStack { Text("Some thing").background(.yellow) Text("Else").background(.blue) } .frame(width: 100, height:100) .background(.brown) } } } }
TabView能实现该功能,显然这是可行的(苹果已实现)!
无效方案
- 将内容私下包装在自定义
Layout中:Layout无法隐藏子视图。 - 将内容作为AnyView数组接收: 不符合SwiftUI的使用习惯,且必须使用
AnyView,会严重影响性能。 - 显式列出子视图并为每个视图添加显示/隐藏逻辑: 封装性差,不符合期望的API设计。
内容的提问来源于stack exchange,提问作者rgeorge
相关产品推荐
相关产品推荐

