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

SwiftUI自定义带分页样式TabView的TabBarItem显示异常问题

SwiftUI自定义分页TabView:TabBarItem无法正常显示问题

我在SwiftUI中尝试实现一个带分页功能(.tabViewStyle(.page()))的自定义TabView,目前大部分功能已完成,但所有TabBarItem无法正常显示。
我使用PreferenceKey来保证TabBar的顺序与闭包中添加的顺序一致,但运行时TabBarItem会先加入数组后又被移除,无法正常工作。
此前通过将枚举设为CaseIterable,并用ForEach(TabBarItems.allCases)实现了功能,但我希望TabBar的顺序由闭包中的添加顺序自然决定。

容器代码

struct TabViewContainer<Content : View>: View {
  @Binding private var selection: TabBarItem
  @State private var tabs: [TabBarItem] = []
  var content: Content

  init(selection: Binding<TabBarItem>, @ViewBuilder content: () -> Content) {
    self._selection = selection
    self.content = content()
  }

  var body: some View {
    ZStack(alignment: .bottom) {
      TabView(selection: $selection) {
        content
      }
      .tabViewStyle(.page(indexDisplayMode: .never))
      tabBarItems()
    }
    .onPreferenceChange(TabBarItemsPreferenceKey.self) { self.tabs = $0 }
  }

  private func tabBarItems() -> some View {
    HStack(spacing: 10) {
      ForEach(tabs) { tab in
        Button {
          selection = tab
        } label: {
          tabButton(tab: tab)
        }
      }
    }
    .padding(.horizontal)
    .frame(maxWidth: .infinity)
    .padding(.top, 8)
    .background(Color(uiColor: .systemGray6))
  }

  private func tabButton(tab: TabBarItem) -> some View {
    VStack(spacing: 0) {
      Image(icon: tab.icon)
        .font(.system(size: 16))
        .frame(maxWidth: .infinity, minHeight: 28)
      Text(tab.title)
        .font(.system(size: 10, weight: .medium, design: .rounded))
    }
    .foregroundColor(selection == tab ? tab.colour : .gray)
  }
}

PreferenceKey与视图修饰符代码

struct TabBarItemsPreferenceKey: PreferenceKey {
  static var defaultValue: [TabBarItem] = []
  static func reduce(value: inout [TabBarItem], nextValue: () -> [TabBarItem]) {
    value += nextValue()
  }
}

struct TabBarItemViewModifier: ViewModifier {
  let tab: TabBarItem
  func body(content: Content) -> some View {
    content.preference(key: TabBarItemsPreferenceKey.self, value: [tab])
  }
}

extension View {
  func tabBarItem(_ tab: TabBarItem) -> some View {
    modifier(TabBarItemViewModifier(tab: tab))
  }
}

演示视图代码

struct TabSelectionView: View {
  @State private var selection: TabBarItem = .itinerary
  var body: some View {
    TabViewContainer(selection: $selection) {
      PhraseView()
        .tabBarItem(.phrases)
      ItineraryView()
        .tabBarItem(.itinerary)
      BudgetView()
        .tabBarItem(.budget)
      BookingView()
        .tabBarItem(.bookings)
      PackingListView()
        .tabBarItem(.packing)
    }
  }
}

效果对比

预期效果当前效果
底部稳定显示全部5个TabBarItem,点击可切换对应页面TabBarItem短暂显示后消失,无法正常展示所有标签

内容的提问来源于stack exchange,提问作者markb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 09:05:14