Это происходит только в этом направлении, при возврате к состоянию по умолчанию никогда не мерцает. Это происходит с перерывами, но его легко воспроизвести, переключив несколько раз.
Я пробовал .contentTransition(.identity), .symbolEffectsRemoved(), откладывал обновление состояния с помощью Task и реструктуризировал панель инструментов, ничего из этого не помогло.
Минимальная цель — iOS 18, и это происходит только на iOS 26+.
Будем признательны за разъяснения.
Gif-репродукция:

Минимальная репродукция ниже:
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()
}
Подробнее здесь: https://stackoverflow.com/questions/798 ... r-1-second
Мобильная версия