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
相关产品推荐
相关产品推荐

