iOS 26+中Toolbar Menu图标切换symbolVariant从.none到.fill时间歇性短暂消失问题求助
大家好,最近做SwiftUI项目时碰到了一个头疼的UI问题,想请教下各位大佬:
我在工具栏里实现了一个Menu,它的图标会根据内嵌的Picker选择结果,动态切换.symbolVariant和.foregroundStyle。但发现当从默认状态(无变体、主色调)切换到激活状态(.fill、蓝色)时,图标有时候会突然消失大概一秒钟,之后才会以正确的样式重新显示出来。
问题的几个特点:
- 只在默认→激活这个切换方向出现,切回默认状态时完全不会有闪烁问题
- 属于间歇性问题,但多切换几次Picker选项就能轻松复现
我已经尝试了几种常见的解决方案,但都没能解决这个问题:
- 给图标添加
.contentTransition(.identity) - 使用
.symbolEffectsRemoved()移除系统默认效果 - 通过
Task延迟状态更新,避免同步刷新可能的冲突 - 重构了整个Toolbar的结构,调整布局逻辑
我的项目最低兼容版本是iOS 18,而且这个问题只在iOS 26+系统上出现。
希望有遇到过类似问题或者了解SwiftUI底层渲染逻辑的朋友能给我一些思路,非常感谢!
问题演示:

最小复现代码:
import SwiftUI // MARK: - Filter Enum enum ItemFilter: String, CaseIterable, Identifiable { case all case onlySystem case onlyCustom var id: Self { self } var title: String { switch self { case .all: "All" case .onlySystem: "Only system" case .onlyCustom: "Only custom" } } var icon: String { switch self { case .all: "square.grid.2x2.fill" case .onlySystem: "gearshape.fill" case .onlyCustom: "person.fill" } } } // MARK: - Sample Data struct SampleItem: Identifiable, Equatable { let id: String let name: String let isSystem: Bool } let systemItems: [SampleItem] = [ SampleItem(id: "s1", name: "Food & Groceries", isSystem: true), SampleItem(id: "s2", name: "Transportation", isSystem: true), SampleItem(id: "s3", name: "Entertainment", isSystem: true), SampleItem(id: "s4", name: "Healthcare", isSystem: true), SampleItem(id: "s5", name: "Utilities", isSystem: true), SampleItem(id: "s6", name: "Education", isSystem: true), ] let customItems: [SampleItem] = [ SampleItem(id: "c1", name: "Coffee", isSystem: false), SampleItem(id: "c2", name: "Gym Membership", isSystem: false), SampleItem(id: "c3", name: "Streaming Services", isSystem: false), SampleItem(id: "c4", name: "Pet Supplies", isSystem: false), ] // MARK: - ContentView struct ContentView: View { @State private var showSheet = false var body: some View { VStack(spacing: 20) { Text("Toolbar Flicker Test") .font(.title2.bold()) Button("Open Selection Sheet") { showSheet = true } .buttonStyle(.borderedProminent) } .sheet(isPresented: $showSheet) { SelectionSheet() } } } // MARK: - SelectionSheet struct SelectionSheet: View { @Environment(\.dismiss) private var dismiss @State private var query = "" @State private var selectedFilter: ItemFilter = .all @State private var selection: SampleItem? private let menuIcon = "line.3.horizontal.decrease.circle" private var filteredSystemItems: [SampleItem] { let base: [SampleItem] switch selectedFilter { case .all, .onlySystem: base = systemItems case .onlyCustom: base = [] } if query.isEmpty { return base } return base.filter { $0.name.localizedStandardContains(query) } } private var filteredCustomItems: [SampleItem] { let base: [SampleItem] switch selectedFilter { case .all, .onlyCustom: base = customItems case .onlySystem: base = [] } if query.isEmpty { return base } return base.filter { $0.name.localizedStandardContains(query) } } var body: some View { NavigationStack { List { if !filteredSystemItems.isEmpty { Section("System") { ForEach(filteredSystemItems) { item in itemRow(item) } } } if !filteredCustomItems.isEmpty { Section("Custom") { ForEach(filteredCustomItems) { item in itemRow(item) } } } if filteredSystemItems.isEmpty && filteredCustomItems.isEmpty { ContentUnavailableView.search(text: query) } } .navigationTitle("Categories") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { let filterBinding = Binding( get: { selectedFilter }, set: { updatedFilter in selectedFilter = updatedFilter } ) Menu { Section { Picker("Filter Items", selection: filterBinding) { ForEach(ItemFilter.allCases) { filter in Label(filter.title, systemImage: filter.icon) .tag(filter) } } .pickerStyle(.inline) } } label: { Image(systemName: menuIcon) .symbolVariant(selectedFilter == .all ? .none : .fill) .foregroundStyle(selectedFilter == .all ? .primary : Color.blue) } } ToolbarItem(placement: .topBarLeading) { Button("Done") { dismiss() } } } .searchable( text: $query, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search categories" ) } } private func itemRow(_ item: SampleItem) -> some View { Button { selection = item dismiss() } label: { HStack { Circle() .fill(item.isSystem ? Color.orange.opacity(0.15) : Color.blue.opacity(0.15)) .frame(width: 36, height: 36) .overlay { Image(systemName: item.isSystem ? "gearshape.fill" : "person.fill") .font(.system(size: 14, weight: .semibold)) .foregroundStyle(item.isSystem ? .orange : .blue) } Text(item.name) .foregroundStyle(.primary) Spacer() if selection?.id == item.id { Image(systemName: "checkmark") .foregroundStyle(.tint) } } } } } #Preview { ContentView() }
备注:内容来源于stack exchange,提问作者Vitor
相关产品推荐
相关产品推荐

