You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 02:10:26