Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

Posts under SwiftUI tag

200 Posts

Post

Replies

Boosts

Views

Activity

Delay when using ResultsObserver over @Query?
I was testing how to use ResultsObserver on a ViewModel in SwiftData. In Xcode 27, Developer v1, I have the following view import SwiftUI import SwiftData @Model class TaskItem { var name: String var priority: Int init(name: String, priority: Int) { self.name = name self.priority = priority } } @Observable @MainActor class RandomViewModel { let observer: ResultsObserver<TaskItem, Never> @ObservationIgnored private var token: ObservationTracking.Token? var tasks: FetchResultsCollection<TaskItem> { observer.results } init(context: ModelContext) { let descriptor = FetchDescriptor<TaskItem>( sortBy: [SortDescriptor(\.name, order: .reverse)] ) observer = try! ResultsObserver(fetchDescriptor: descriptor, modelContext: context) } } struct RandomView: View { @State var viewModel: RandomViewModel? @Environment(\.modelContext) private var modelContext var body: some View { VStack { if let viewModel { List(viewModel.tasks) { foo in Text(foo.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(viewModel.observer.results.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } else { Text("Hello, World!") } } .task { if viewModel == nil { viewModel = RandomViewModel(context: modelContext) } } } } func testContainer() -> ModelContainer { let schema = Schema([ Item.self, TaskItem.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) let container = try! ModelContainer(for: schema, configurations: [modelConfiguration]) let modelContext = container.mainContext for i in 1...20 { let item = TaskItem(name: "Sample Task \(i)", priority: Int.random(in: 1...5)) modelContext.insert(item) } return container } #Preview { NavigationStack { RandomView() } .modelContainer(testContainer()) } When I run the Preview or the simulator, the UI takes a while to actually load and show the results. If I try a version using @Query this doesn't happen import SwiftData import SwiftUI struct RandomQueryView: View { @Environment(\.modelContext) private var modelContext @Query(sort: [SortDescriptor(\TaskItem.name, order: .reverse)]) private var tasks: [TaskItem] var body: some View { List(tasks) { task in Text(task.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(tasks.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } } #Preview { NavigationStack { RandomQueryView() } .modelContainer(testContainer()) } Is this a bug in SwiftData ResultsObserver? or am I using it wrong? I add a recording of my simulator showing the difference
1
0
946
Jun ’26
Liquid Glass tab bar doesn't update its background on tab switch until I scroll — expected? Workaround?
Hi, On iOS 26 I'm seeing a behavior with the new Liquid Glass tab bar in SwiftUI and I can't tell if it's expected or if there's a supported workaround. When I switch tabs in a TabView, the floating Liquid Glass tab bar keeps the glass appearance it derived from the previous tab's content. It only refreshes to match the newly selected tab once I scroll the new tab's scroll view — even by a single point. In Apple's own apps (e.g. Home) the bar updates immediately on tab change, which makes me think this isn't intended. I reduced it to a minimal example — no images, no glassEffect, no NavigationStack, just gradients: struct ContentView: View { enum TabID: Hashable { case blue, green, dark } @State private var selection: TabID = .blue var body: some View { TabView(selection: $selection) { Tab("Blue", systemImage: "drop.fill", value: .blue) { Page(colors: [.blue, .indigo]) } Tab("Green", systemImage: "leaf.fill", value: .green) { Page(colors: [.green, .teal]) } Tab("Dark", systemImage: "moon.fill", value: .dark) { Page(colors: [.gray, .black]) } } } } struct Page: View { let colors: [Color] var body: some View { ZStack { LinearGradient(colors: colors, startPoint: .top, endPoint: .bottom) .ignoresSafeArea() ScrollView { ForEach(0..<40, id: \.self) { Text("Row \($0)") .foregroundStyle(.white) .frame(maxWidth: .infinity, alignment: .leading) .padding() } } } } } Steps to reproduce: Run on a real device (iPhone 17 Pro Max, iOS 26.5.1, Xcode 26). Switch between the three tabs without scrolling. Expected: the tab bar's glass tint adapts to the destination tab's gradient immediately on switch. Actual: the bar keeps the previous tab's tint until I scroll the new view ~1pt. What I've already tried (no luck): Both the modern Tab API and the legacy .tabItem / .tag style — same behavior. Faking a scroll with setContentOffset (animated and non-animated) — doesn't reliably trigger the refresh; only a genuine user scroll does. toolbarBackgroundVisibility(...) and forcing a color scheme — no effect. Questions: Is this a known issue / expected behavior in iOS 26? Is there a supported way to make the tab bar re-sample its Liquid Glass backdrop when the selected tab changes (without requiring a user scroll)? I've also filed it via Feedback Assistant. Thanks! Configuration: iPhone 17 Pro Max, iOS 26.5.1, Xcode 26.
0
0
391
Jun ’26
NavigationSplitView no longer pops back to the root view when selection = nil in iOS 26.4 (with a nested TabView)
In iOS 26.4 (iPhone, not iPad), when a NavigationSplitView is combined with a nested TabView, it no longer pops back to the root sidebar view when the List selection is set to nil. This has been working fine for at least a few years, but has just stopped working in iOS 26.4. Here's a minimal working example: import SwiftUI struct ContentView: View { @State var articles: [Article] = [Article(articleTitle: "Dog"), Article(articleTitle: "Cat"), Article(articleTitle: "Mouse")] @State private var selectedArticle: Article? = nil var body: some View { NavigationSplitView { TabView { Tab { List(articles, selection: $selectedArticle) { article in Button { selectedArticle = article } label: { Text(article.title) } } } label: { Label("Explore", systemImage: "binoculars") } } } detail: { Group { if let selectedArticle { Text(selectedArticle.title) } else { Text("No selected article") } } .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", systemImage: "xmark") { selectedArticle = nil } } } } } } struct Article: Identifiable, Hashable { let id: String let title: String init(articleTitle: String) { self.id = articleTitle self.title = articleTitle } } First, I'm aware that nesting a TabView inside a NavigationSplitView is frowned upon: Apple seems to prefer NavigationSplitView nested inside a Tab. However, for my app, that leads to a very confusing user experience. Users quickly get lost because they end up with different articles open in different tabs and it doesn't align well with my core distinction between two "modes": article selection mode and article reading mode. When the user is in article selection mode (sidebar view), they can pick between different ways of selecting an article (Explore, Bookmarks, History, Search), which are implemented as "tabs". When they pick an article from any tab they jump into article reading mode (the detail view). Second, I'm using .navigationBarBackButtonHidden(true) to remove the auto back button that pops back to the sidebar view. This button does still work in iOS 26.4, even with the nested TabView. However, I can't use the auto back button because my detail view is actually a WebView with its own back/forward logic and UI. Therefore, I need a separate close button to exit from the detail view. My close button sets selectedArticle to nil, which (pre-iOS 26.4) would trigger the NavigationSplitView to pop back to the sidebar view. For some reason, in iOS 26.4 the NavigationSplitView doesn't seem to bind correctly to the List's selection parameter, specifically when there's a TabView nested between them. Or, rather, it binds, but fails to pop back when selection becomes nil. One option is to replace NavigationSplitView with NavigationStack (on iPhone). NavigationStack still works with a nested TabView, but it creates other downstream issues for me (as well as forcing me to branch for iPhone and iPad), so I'd prefer to continue using NavigationSplitView. Does anyone have any ideas about how to work around this problem? Is there some way of explicitly telling NavigationSplitView to pop back to the sidebar view on iPhone? (I've tried setting the column visibility but nothing seems to work). Thanks for any help!
2
1
418
Jun ’26
How to build a picker wheel similar as the Calendar App?
How to build the below UI using SwiftUI? I tried to use Picker with wheel style, but it is not the same as the screenshot. The screenshot came from the iOS built-in calendar app. Add a new calendar event Click "Repeat" Choose "Custom" Click "Every day" The required picker wheel will be displayed Picker("Every", selection: $interval) { ForEach(1..<366) { interval in Text("\(interval)").tag(interval) } } .pickerStyle(.wheel)
0
0
262
Jun ’26
How do I get SwiftUI to let me determine a custom frame size for NSTextField
I have a NSViewRepresentable that wraps an NSTextField subclass which is displayed as larger than your typical text field. SwiftUI doesn't seem to allow me to set the size of the view when the underlying is an NSTextField. It forces it as a single line field. I've tried both setting the frame on creation as well as using SwiftUI .frame(width:height:) on the represented view. I always end up with a single line field. struct BigTextField: NSViewRepresentable { @Binding var text: String class Coordinator: NSObject, NSTextFieldDelegate { var parent: BigTextField init(_ parent: BigTextField) { self.parent = parent } func controlTextDidChange(_ obj: Notification) { if let textField = obj.object as? NSTextField { parent.text = textField.stringValue } } } func makeCoordinator() -> Coordinator { Coordinator(self) } func makeNSView(context: Context) -> NSTextField { //let frame = NSRect(x: 0, y: 0, width: 350, height: 140) //let textField = NSTextField(frame: frame) let textField = NSTextField() textField.isEditable = true textField.isBordered = true textField.isBezeled = true textField.delegate = context.coordinator // Assign the coordinator return textField } func updateNSView(_ nsView: NSTextField, context: Context) { if nsView.stringValue != text { nsView.stringValue = text } } } I've also included the SwiftUI declaration which demonstrates the problem. struct ContentView: View { @State var text : String = "Test string" var body: some View { VStack { BigTextField(text: $text) .frame(width: 350, height: 140) } .padding() } } NSTextField can be any arbitrary frame size. I already do this from AppKit but am trying to adapt this custom field to work within SwiftUI. SwiftUI seems to override the sizing of this NSViewRepresentable that I give it. Am I missing something here? Is there some way to override SwiftUI's sizing behavior? Thank you.
0
0
281
Jun ’26
Back gesture not disabled with navigationBarBackButtonHidden(true) when using .zoom transition
[Submitted as FB22226720] For a NavigationStack destination, applying .navigationBarBackButtonHidden(true) hides the back button and also disables the interactive left-edge back gesture when using the standard push navigation transition. However, when the destination uses .navigationTransition(.zoom), the back button is hidden but the left-edge back gesture is still available—it can still be dismissed even though back is intentionally suppressed. This creates inconsistent behavior between navigation transition styles. navigationBarBackButtonHidden(_:) works with a standard push transition, but not with .navigationTransition(.zoom). In the code below, .interactiveDismissDisabled(true) is also applied as another attempt to suppress the back-swipe gesture, but it has no effect. As a result, there’s currently no clean way to prevent back navigation when using the zoom transition. REPRO STEPS Create an iOS project then replace ContentView with code below, build and run. Leave nav type set to List Push. Open an item. Verify there is no back button, then try the left-edge back gesture. Return to the root view. Change nav type to Grid Zoom. Open an item. Verify there is no back button, then try the left-edge back gesture. ACTUAL In List Push mode, the left-edge back gesture is prevented. In Grid Zoom mode, the back button is hidden, but the left-edge back gesture still works and returns to the previous view. EXPECTED Behavior should be consistent across navigation transition styles. If this configuration is meant to suppress interactive backward navigation for a destination, it should also suppress the left-edge back gesture when using .navigationTransition(.zoom). SCREEN RECORDING SAMPLE CODE struct ContentView: View { private enum NavigationMode: String, CaseIterable { case listPush = "List Push" case gridZoom = "Grid Zoom" } @Namespace private var namespace @State private var navigationMode: NavigationMode = .listPush private let colors: [Color] = [.red, .blue] var body: some View { NavigationStack { VStack(spacing: 16) { Picker("Navigation Type", selection: $navigationMode) { ForEach(NavigationMode.allCases, id: \.self) { mode in Text(mode.rawValue).tag(mode) } } .pickerStyle(.segmented) if navigationMode == .gridZoom { HStack { ForEach(colors.indices, id: \.self) { index in NavigationLink(value: index) { VStack { RoundedRectangle(cornerRadius: 14) .fill(colors[index]) .frame(height: 120) Text("Grid Item \(index + 1)") .font(.subheadline.weight(.medium)) } .padding(12) .frame(maxWidth: .infinity) .background(.quaternary.opacity(0.25), in: RoundedRectangle(cornerRadius: 16)) .matchedTransitionSource(id: index, in: namespace) } .buttonStyle(.plain) } } } else { ForEach(colors.indices, id: \.self) { index in NavigationLink(value: index) { HStack { Circle() .fill(colors[index]) .frame(width: 24, height: 24) Text("List Item \(index + 1)") Spacer() Image(systemName: "chevron.right") .foregroundStyle(.secondary) } .padding() .background(.quaternary.opacity(0.25), in: RoundedRectangle(cornerRadius: 12)) } .buttonStyle(.plain) } } Spacer() } .padding(20) .navigationTitle("Prevent Back Swipe") .navigationSubtitle("Compare Grid Zoom vs List Push") .navigationDestination(for: Int.self) { index in if navigationMode == .gridZoom { DetailView(color: colors[index]) .navigationTransition(.zoom(sourceID: index, in: namespace)) } else { DetailView(color: colors[index]) } } } } } private struct DetailView: View { @Environment(\.dismiss) private var dismiss let color: Color var body: some View { ZStack { color.ignoresSafeArea() Text("Try left-edge swipe back") .font(.title.bold()) .multilineTextAlignment(.center) .padding(.horizontal, 24) } .navigationBarBackButtonHidden(true) .interactiveDismissDisabled(true) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", action: dismiss.callAsFunction) } } } }
3
1
986
Jun ’26
How to create @Query based on input
Overview I have a view B contains @Query for cars, now this @Query predicate depends on an input which is passed from view A. Current approach I am creating @Query in the init of view B by using _cars. Questions Now how can I compose @Query based on input from view A? Is my approach correct? In my approach Query will be created every time init gets called Or is there a better approach?
2
0
959
Jun ’26
Handling View Creation for Heterogeneous Data
In my project (an Package), I have created an Manager (can be classified as an ViewModel) that will handle state updates throughout the Package Component view: Note: The code is simplified for better understanding and to focus on principles behind things I did. The manager does complex things during state updates. public class ComponentManager: ObservedObject { @Published var rows: [any RowProtocol] = [] func updateState(_ newState: any RowProtocolData, id: String) { guard let index = rows.firstIndex(where: { $0.id == id }) else { return } rows[index].updateState(newState) } func getState(id: String) -> any RowProtocolData? { guard let index = rows.firstIndex(where: { $0.id == id }) else { return nil } return rows[index].state } } The RowProtocol is defined as follows: public protocol RowStateProtocol {} public protocol RowProtocol: Identifiable { associatedtype State: RowStateProtocol associatedtype RowView: View var id: String { get } var state: State { get } func updateState(_ newState: State) @MainActor @ViewBuilder func renderRow() -> RowView } extension RowProtocol { func updateState(_ newState: any RowProtocolData) { guard let newState = newState as? State else { return } self.updateState(newState) } } Then in Component View, I need to render the rows based on the underlying type of the row, this where the renderRow() comes in: struct ComponentView: View { @ObservedObject var manager: ComponentManager var body: some View { List { ForEach(manager.rows, id: \.id) { row in HStack { // This HStack prevent List from initing all rows due to AnyView. AnyView(row.renderRow()) } } } } } The row views will be accepting binding to the state of the row and update their state, let says we have a TextRow and a ToggleRow: struct TextRow: RowProtocol { var id: String var state: TextRowState func updateState(_ newState: TextRowState) { self.state = newState } } struct ToggleRow: RowProtocol { var id: String var state: ToggleRowState func updateState(_ newState: ToggleRowState) { self.state = newState } } In this, offcourse we cannot create an binding directly to the state of the row, since the state are through the manager and the row data won't have access to the manager. So I created an property wrapped that use the closures passed by the manager into environment to create the binding and an view that will give the binding to the content view: extenstion EnvironmentValues { @Entry internal var getState: (String) -> any RowStateProtocol? @Entry internal var updateState: (any RowStateProtocol, String) -> Void } @propertyWrapper struct RowStateBinding<State: RowStateProtocol & Equatable>: DynamicProperty { @Environment(\.getState) private var getState @Environment(\.updateState) private var updateState private let id: String init(id: String) { self.id = id } var wrappedValue: State { get { getState(id) as! State } nonmutating set { if wrappedValue != newValue { // only update for an new change, since set can be triggered for any number of reasons. updateState(newValue, id) } } } var projectedValue: Binding<State> { Binding( get: { self.wrappedValue }, set: { newValue in self.wrappedValue = newValue } ) } } struct RowStateBindingView<Content: View, State: RowStateProtocol & Equatable>: View { @RowStateBinding<State> private var state: State private let content: (Binding<State>) -> Content init(id: String, @ViewBuilder content: @escaping (Binding<State>) -> Content) { self._state = RowStateBinding(id: id) self.content = content } var body: some View { content($state) } } and in the renderRows: struct TextRowView: View { @Binding var text: TextRowState var body: some View { TextField("Enter text", text: $text.text) } } extension TextRow { func renderRow() -> some View { RowStateBindingView(id: id) { state in TextField("Enter text", text: state.text) } } } struct ToggleRowView: View { @Binding var state: ToggleRowState var body: some View { Toggle("Toggle", isOn: $state.isOn) } } extension ToggleRow { func renderRow() -> some View { RowStateBindingView(id: id) { state in Toggle("Toggle", isOn: state.isOn) } } } This way, I can adopt any view as an row view and most importantly, the view can be completely independent of the manager and used as an standalone view. Also clients of the library can create their own custom rows by just conforming to the RowProtocol and creating the view for it, without worrying about how the state management works. The manager will handle all the state updates. I prefer using stucts over classes for rows and states, since its easier to manage state updates. What do you think about this approach? Do you see any potential issues with this? Is there a better way to achieve this?
0
0
233
Jun ’26
UIView wrapper around a View
I couldn't decide whether to post this question here or in SwiftUI Q&A as there's a lot of overlaps. We're trying to create something similar to UIViewRepresentable for UIKit. This might not work for complicated cases where the View has many pieces but as long as it works for simple cases, we're happy. The only problem right now is figuring out the correct height. Currently, the height anchor is assigned to CGFloat.greatestFiniteMagnitude, which works but when inspecting the layout in View Hierarchy, it appears the wrapped view is getting stretched all the way down. Also, sometimes View Hierarchy isn't able to draw the wrapped View and I'm unsure if it's a problem of View Hierarchy or our implementation. final public class SwiftUIConfigurationContainerView<T: View>: UIView { private var contentView: UIView? public override var intrinsicContentSize: CGSize { contentView?.intrinsicContentSize ?? super.intrinsicContentSize } private var preferredContentSize: CGSize? public init(@ViewBuilder _ content: @escaping () -> T) { super.init(frame: .zero) setUpContentView(content) } @available(*, unavailable) required init?(coder: NSCoder) { return nil } private func setUpContentView(_ content: @escaping () -> T) { let contentView = UIHostingConfiguration { [weak self] in VStack(spacing: .zero) { content() .onGeometryChange(for: CGSize.self, of: \.size) { size in self?.preferredContentSize = size self?.invalidateIntrinsicContentSize() } .frame(maxWidth: .infinity, alignment: .center) Spacer(minLength: .zero) } } .minSize(width: .zero, height: .zero) .margins(.all, .zero) .makeContentView() self.contentView = contentView addSubview(contentView) contentView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ contentView.leadingAnchor.constraint(equalTo: leadingAnchor), contentView.trailingAnchor.constraint(equalTo: trailingAnchor), contentView.topAnchor.constraint(equalTo: topAnchor), contentView.heightAnchor.constraint(equalToConstant: CGFloat.greatestFiniteMagnitude), ]) } }
0
0
388
Jun ’26
How to detect backspace in SwiftUI TextField without falling back to UIViewRepresentable?
I'm building a multi-box PIN/OTP input in SwiftUI. In UIKit, I used UITextFieldDelegate to detect backspace presses on an empty field to move focus backward. SwiftUI’s .onChange(of: text) only triggers when text is actually deleted, completely missing backspaces on an already empty field. Is there a pure SwiftUI way to handle this now, or are we still forced to wrap UITextField via UIViewRepresentable?
1
0
264
Jun ’26
@State changes in Xcode 27 are causing variable definitions spanning multiple lines to produce unexpected compiler errors.
On Xcode 27, the compiler incorrectly errors when a @State variable definition is placed on multiple lines. The code compiles without any issues on Xcode 26 and is valid Swift. The issue is fixed if the var definition is placed on a single line. The following code produces issues: @State internal var bodyText = "Hi" However, the code below works: @State internal var bodyText = "Hi" The issue is reproducible in any new project with a simple view: import SwiftUI import Playgrounds @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State internal var bodyText = "Hi" var body: some View { Text(bodyText) .padding() } } #Preview { ContentView() } The expected behavior is for valid Swift code to not trigger compiler error. Filed FB23044343
1
0
463
Jun ’26
Reorderable with Xcode previews
I was playing around with the brand-new reorderable API and couldn't get it to work within previews. Is there a specific way to get previews to work with reorderable, or do I need to compile every time? I was also curious if there will be an addition to the Array generic struct, as it seems like the solution there currently is is just an extension, although the way it's being promoted makes it seem like it is built into the type.
2
0
289
Jun ’26
tvOS SwiftUI App Bugfixes
Hi :-) I need some advice to fix the following issues in SwiftUI. I don't have the source code myself, but I'd like to help the programmer fix the problem quickly. So I'm looking for a few lines of Example-Code that I can show these Code-Lines to help resolve this quickly. 1. "Jumping shadow" when swiping => The Shadow under the Genre.Buttons jumps when you swipe through them. 2. Liquid Glass Flicker => The Liquid Glass EDGE on a poster or on the buttons flickers (abruptly disappear) when switching from one page to another Can someone help me? Bets regards, Christian :)
0
0
309
Jun ’26
How to present a View above everything in SwiftUI?
Hello, I'm trying to present an app overlay (like an HUD) that should appear on top of everything (the app UI could be the root content view or a modal presented from the content view or a modal over a modal presented from the content view, etc.). If I use a ZStack for example, the issue is that the view is not visible if the ZStack is presenting a modal for example. In UIKit, I think we can use instantiate another UIWindow to show content above the top window of the app (what a native alert does if I'm not wrong). What would be the equivalent in SwiftUI? How could I create this? Thanks, Axel
2
0
236
Jun ’26
Wrong position of searchable component on first render
Hey all, I found a weird behaviour with the searchable component. I created a custom bottom nav bar (because I have custom design in my app) to switch between screens. On one screen I display a List component with the searchable component. Whenever I enter the search screen the first time, the searchable component is displayed at the bottom. This is wrong. It should be displayed at the top under the navigationTitle. When I enter the screen a second time, everything is correct. This behaviour can be reproduced on all iOS 26 versions on the simulator and on a physical device with debug and release build. On iOS 18 everything works fine. Steps to reproduce: Cold start of the app Click on Search TabBarIcon (searchable wrong location) Click on Home TabBarIcon Click on Search TabBarIcon (searchable correct location) Simple code example: import SwiftUI struct ContentView: View { @State var selectedTab: Page = Page.main var body: some View { NavigationStack { ZStack { VStack { switch selectedTab { case .main: MainView() case .search: SearchView() } } VStack { Spacer() VStack(spacing: 0) { HStack(spacing: 0) { TabBarIcon(iconName: "house", selected: selectedTab == .main, displayName: "Home") .onTapGesture { selectedTab = .main } TabBarIcon(iconName: "magnifyingglass", selected: selectedTab == .search, displayName: "Search") .onTapGesture { selectedTab = .search } } .frame(maxWidth: .infinity) .frame(height: 55) .background(Color.gray) } .ignoresSafeArea(.all, edges: .bottom) } } } } } struct TabBarIcon: View { let iconName: String let selected: Bool let displayName: String var body: some View { ZStack { VStack { Image(systemName: iconName) .resizable() .renderingMode(.template) .aspectRatio(contentMode: .fit) .foregroundColor(Color.black) .frame(width: 22, height: 22) Text(displayName) .font(Font.system(size: 10)) } } .frame(maxWidth: .infinity) } } enum Page { case main case search } struct MainView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() .navigationTitle("Home") } } struct SearchView: View { @State private var searchText = "" let items = [ "Apple", "Banana", "Pear", "Strawberry", "Orange", "Peach", "Grape", "Mango" ] var filteredItems: [String] { if searchText.isEmpty { return items } else { return items.filter { $0.localizedCaseInsensitiveContains(searchText) } } } var body: some View { List(filteredItems, id: \.self) { item in Text(item) } .navigationTitle("Fruits") .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search") } }
5
0
493
Jun ’26
Delay when using ResultsObserver over @Query?
I was testing how to use ResultsObserver on a ViewModel in SwiftData. In Xcode 27, Developer v1, I have the following view import SwiftUI import SwiftData @Model class TaskItem { var name: String var priority: Int init(name: String, priority: Int) { self.name = name self.priority = priority } } @Observable @MainActor class RandomViewModel { let observer: ResultsObserver<TaskItem, Never> @ObservationIgnored private var token: ObservationTracking.Token? var tasks: FetchResultsCollection<TaskItem> { observer.results } init(context: ModelContext) { let descriptor = FetchDescriptor<TaskItem>( sortBy: [SortDescriptor(\.name, order: .reverse)] ) observer = try! ResultsObserver(fetchDescriptor: descriptor, modelContext: context) } } struct RandomView: View { @State var viewModel: RandomViewModel? @Environment(\.modelContext) private var modelContext var body: some View { VStack { if let viewModel { List(viewModel.tasks) { foo in Text(foo.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(viewModel.observer.results.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } else { Text("Hello, World!") } } .task { if viewModel == nil { viewModel = RandomViewModel(context: modelContext) } } } } func testContainer() -> ModelContainer { let schema = Schema([ Item.self, TaskItem.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) let container = try! ModelContainer(for: schema, configurations: [modelConfiguration]) let modelContext = container.mainContext for i in 1...20 { let item = TaskItem(name: "Sample Task \(i)", priority: Int.random(in: 1...5)) modelContext.insert(item) } return container } #Preview { NavigationStack { RandomView() } .modelContainer(testContainer()) } When I run the Preview or the simulator, the UI takes a while to actually load and show the results. If I try a version using @Query this doesn't happen import SwiftData import SwiftUI struct RandomQueryView: View { @Environment(\.modelContext) private var modelContext @Query(sort: [SortDescriptor(\TaskItem.name, order: .reverse)]) private var tasks: [TaskItem] var body: some View { List(tasks) { task in Text(task.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(tasks.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } } #Preview { NavigationStack { RandomQueryView() } .modelContainer(testContainer()) } Is this a bug in SwiftData ResultsObserver? or am I using it wrong? I add a recording of my simulator showing the difference
Replies
1
Boosts
0
Views
946
Activity
Jun ’26
Best position for dismiss button on sheets?
Is there any guidance on changes here between iOS 26 & 27? To go .topLeading or .topTrailing? That is the question. iOS 26 iOS 27
Replies
1
Boosts
0
Views
850
Activity
Jun ’26
Liquid Glass tab bar doesn't update its background on tab switch until I scroll — expected? Workaround?
Hi, On iOS 26 I'm seeing a behavior with the new Liquid Glass tab bar in SwiftUI and I can't tell if it's expected or if there's a supported workaround. When I switch tabs in a TabView, the floating Liquid Glass tab bar keeps the glass appearance it derived from the previous tab's content. It only refreshes to match the newly selected tab once I scroll the new tab's scroll view — even by a single point. In Apple's own apps (e.g. Home) the bar updates immediately on tab change, which makes me think this isn't intended. I reduced it to a minimal example — no images, no glassEffect, no NavigationStack, just gradients: struct ContentView: View { enum TabID: Hashable { case blue, green, dark } @State private var selection: TabID = .blue var body: some View { TabView(selection: $selection) { Tab("Blue", systemImage: "drop.fill", value: .blue) { Page(colors: [.blue, .indigo]) } Tab("Green", systemImage: "leaf.fill", value: .green) { Page(colors: [.green, .teal]) } Tab("Dark", systemImage: "moon.fill", value: .dark) { Page(colors: [.gray, .black]) } } } } struct Page: View { let colors: [Color] var body: some View { ZStack { LinearGradient(colors: colors, startPoint: .top, endPoint: .bottom) .ignoresSafeArea() ScrollView { ForEach(0..<40, id: \.self) { Text("Row \($0)") .foregroundStyle(.white) .frame(maxWidth: .infinity, alignment: .leading) .padding() } } } } } Steps to reproduce: Run on a real device (iPhone 17 Pro Max, iOS 26.5.1, Xcode 26). Switch between the three tabs without scrolling. Expected: the tab bar's glass tint adapts to the destination tab's gradient immediately on switch. Actual: the bar keeps the previous tab's tint until I scroll the new view ~1pt. What I've already tried (no luck): Both the modern Tab API and the legacy .tabItem / .tag style — same behavior. Faking a scroll with setContentOffset (animated and non-animated) — doesn't reliably trigger the refresh; only a genuine user scroll does. toolbarBackgroundVisibility(...) and forcing a color scheme — no effect. Questions: Is this a known issue / expected behavior in iOS 26? Is there a supported way to make the tab bar re-sample its Liquid Glass backdrop when the selected tab changes (without requiring a user scroll)? I've also filed it via Feedback Assistant. Thanks! Configuration: iPhone 17 Pro Max, iOS 26.5.1, Xcode 26.
Replies
0
Boosts
0
Views
391
Activity
Jun ’26
NavigationSplitView no longer pops back to the root view when selection = nil in iOS 26.4 (with a nested TabView)
In iOS 26.4 (iPhone, not iPad), when a NavigationSplitView is combined with a nested TabView, it no longer pops back to the root sidebar view when the List selection is set to nil. This has been working fine for at least a few years, but has just stopped working in iOS 26.4. Here's a minimal working example: import SwiftUI struct ContentView: View { @State var articles: [Article] = [Article(articleTitle: "Dog"), Article(articleTitle: "Cat"), Article(articleTitle: "Mouse")] @State private var selectedArticle: Article? = nil var body: some View { NavigationSplitView { TabView { Tab { List(articles, selection: $selectedArticle) { article in Button { selectedArticle = article } label: { Text(article.title) } } } label: { Label("Explore", systemImage: "binoculars") } } } detail: { Group { if let selectedArticle { Text(selectedArticle.title) } else { Text("No selected article") } } .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", systemImage: "xmark") { selectedArticle = nil } } } } } } struct Article: Identifiable, Hashable { let id: String let title: String init(articleTitle: String) { self.id = articleTitle self.title = articleTitle } } First, I'm aware that nesting a TabView inside a NavigationSplitView is frowned upon: Apple seems to prefer NavigationSplitView nested inside a Tab. However, for my app, that leads to a very confusing user experience. Users quickly get lost because they end up with different articles open in different tabs and it doesn't align well with my core distinction between two "modes": article selection mode and article reading mode. When the user is in article selection mode (sidebar view), they can pick between different ways of selecting an article (Explore, Bookmarks, History, Search), which are implemented as "tabs". When they pick an article from any tab they jump into article reading mode (the detail view). Second, I'm using .navigationBarBackButtonHidden(true) to remove the auto back button that pops back to the sidebar view. This button does still work in iOS 26.4, even with the nested TabView. However, I can't use the auto back button because my detail view is actually a WebView with its own back/forward logic and UI. Therefore, I need a separate close button to exit from the detail view. My close button sets selectedArticle to nil, which (pre-iOS 26.4) would trigger the NavigationSplitView to pop back to the sidebar view. For some reason, in iOS 26.4 the NavigationSplitView doesn't seem to bind correctly to the List's selection parameter, specifically when there's a TabView nested between them. Or, rather, it binds, but fails to pop back when selection becomes nil. One option is to replace NavigationSplitView with NavigationStack (on iPhone). NavigationStack still works with a nested TabView, but it creates other downstream issues for me (as well as forcing me to branch for iPhone and iPad), so I'd prefer to continue using NavigationSplitView. Does anyone have any ideas about how to work around this problem? Is there some way of explicitly telling NavigationSplitView to pop back to the sidebar view on iPhone? (I've tried setting the column visibility but nothing seems to work). Thanks for any help!
Replies
2
Boosts
1
Views
418
Activity
Jun ’26
How to build a picker wheel similar as the Calendar App?
How to build the below UI using SwiftUI? I tried to use Picker with wheel style, but it is not the same as the screenshot. The screenshot came from the iOS built-in calendar app. Add a new calendar event Click "Repeat" Choose "Custom" Click "Every day" The required picker wheel will be displayed Picker("Every", selection: $interval) { ForEach(1..<366) { interval in Text("\(interval)").tag(interval) } } .pickerStyle(.wheel)
Replies
0
Boosts
0
Views
262
Activity
Jun ’26
How do I get SwiftUI to let me determine a custom frame size for NSTextField
I have a NSViewRepresentable that wraps an NSTextField subclass which is displayed as larger than your typical text field. SwiftUI doesn't seem to allow me to set the size of the view when the underlying is an NSTextField. It forces it as a single line field. I've tried both setting the frame on creation as well as using SwiftUI .frame(width:height:) on the represented view. I always end up with a single line field. struct BigTextField: NSViewRepresentable { @Binding var text: String class Coordinator: NSObject, NSTextFieldDelegate { var parent: BigTextField init(_ parent: BigTextField) { self.parent = parent } func controlTextDidChange(_ obj: Notification) { if let textField = obj.object as? NSTextField { parent.text = textField.stringValue } } } func makeCoordinator() -> Coordinator { Coordinator(self) } func makeNSView(context: Context) -> NSTextField { //let frame = NSRect(x: 0, y: 0, width: 350, height: 140) //let textField = NSTextField(frame: frame) let textField = NSTextField() textField.isEditable = true textField.isBordered = true textField.isBezeled = true textField.delegate = context.coordinator // Assign the coordinator return textField } func updateNSView(_ nsView: NSTextField, context: Context) { if nsView.stringValue != text { nsView.stringValue = text } } } I've also included the SwiftUI declaration which demonstrates the problem. struct ContentView: View { @State var text : String = "Test string" var body: some View { VStack { BigTextField(text: $text) .frame(width: 350, height: 140) } .padding() } } NSTextField can be any arbitrary frame size. I already do this from AppKit but am trying to adapt this custom field to work within SwiftUI. SwiftUI seems to override the sizing of this NSViewRepresentable that I give it. Am I missing something here? Is there some way to override SwiftUI's sizing behavior? Thank you.
Replies
0
Boosts
0
Views
281
Activity
Jun ’26
Back gesture not disabled with navigationBarBackButtonHidden(true) when using .zoom transition
[Submitted as FB22226720] For a NavigationStack destination, applying .navigationBarBackButtonHidden(true) hides the back button and also disables the interactive left-edge back gesture when using the standard push navigation transition. However, when the destination uses .navigationTransition(.zoom), the back button is hidden but the left-edge back gesture is still available—it can still be dismissed even though back is intentionally suppressed. This creates inconsistent behavior between navigation transition styles. navigationBarBackButtonHidden(_:) works with a standard push transition, but not with .navigationTransition(.zoom). In the code below, .interactiveDismissDisabled(true) is also applied as another attempt to suppress the back-swipe gesture, but it has no effect. As a result, there’s currently no clean way to prevent back navigation when using the zoom transition. REPRO STEPS Create an iOS project then replace ContentView with code below, build and run. Leave nav type set to List Push. Open an item. Verify there is no back button, then try the left-edge back gesture. Return to the root view. Change nav type to Grid Zoom. Open an item. Verify there is no back button, then try the left-edge back gesture. ACTUAL In List Push mode, the left-edge back gesture is prevented. In Grid Zoom mode, the back button is hidden, but the left-edge back gesture still works and returns to the previous view. EXPECTED Behavior should be consistent across navigation transition styles. If this configuration is meant to suppress interactive backward navigation for a destination, it should also suppress the left-edge back gesture when using .navigationTransition(.zoom). SCREEN RECORDING SAMPLE CODE struct ContentView: View { private enum NavigationMode: String, CaseIterable { case listPush = "List Push" case gridZoom = "Grid Zoom" } @Namespace private var namespace @State private var navigationMode: NavigationMode = .listPush private let colors: [Color] = [.red, .blue] var body: some View { NavigationStack { VStack(spacing: 16) { Picker("Navigation Type", selection: $navigationMode) { ForEach(NavigationMode.allCases, id: \.self) { mode in Text(mode.rawValue).tag(mode) } } .pickerStyle(.segmented) if navigationMode == .gridZoom { HStack { ForEach(colors.indices, id: \.self) { index in NavigationLink(value: index) { VStack { RoundedRectangle(cornerRadius: 14) .fill(colors[index]) .frame(height: 120) Text("Grid Item \(index + 1)") .font(.subheadline.weight(.medium)) } .padding(12) .frame(maxWidth: .infinity) .background(.quaternary.opacity(0.25), in: RoundedRectangle(cornerRadius: 16)) .matchedTransitionSource(id: index, in: namespace) } .buttonStyle(.plain) } } } else { ForEach(colors.indices, id: \.self) { index in NavigationLink(value: index) { HStack { Circle() .fill(colors[index]) .frame(width: 24, height: 24) Text("List Item \(index + 1)") Spacer() Image(systemName: "chevron.right") .foregroundStyle(.secondary) } .padding() .background(.quaternary.opacity(0.25), in: RoundedRectangle(cornerRadius: 12)) } .buttonStyle(.plain) } } Spacer() } .padding(20) .navigationTitle("Prevent Back Swipe") .navigationSubtitle("Compare Grid Zoom vs List Push") .navigationDestination(for: Int.self) { index in if navigationMode == .gridZoom { DetailView(color: colors[index]) .navigationTransition(.zoom(sourceID: index, in: namespace)) } else { DetailView(color: colors[index]) } } } } } private struct DetailView: View { @Environment(\.dismiss) private var dismiss let color: Color var body: some View { ZStack { color.ignoresSafeArea() Text("Try left-edge swipe back") .font(.title.bold()) .multilineTextAlignment(.center) .padding(.horizontal, 24) } .navigationBarBackButtonHidden(true) .interactiveDismissDisabled(true) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", action: dismiss.callAsFunction) } } } }
Replies
3
Boosts
1
Views
986
Activity
Jun ’26
How to create @Query based on input
Overview I have a view B contains @Query for cars, now this @Query predicate depends on an input which is passed from view A. Current approach I am creating @Query in the init of view B by using _cars. Questions Now how can I compose @Query based on input from view A? Is my approach correct? In my approach Query will be created every time init gets called Or is there a better approach?
Replies
2
Boosts
0
Views
959
Activity
Jun ’26
Handling View Creation for Heterogeneous Data
In my project (an Package), I have created an Manager (can be classified as an ViewModel) that will handle state updates throughout the Package Component view: Note: The code is simplified for better understanding and to focus on principles behind things I did. The manager does complex things during state updates. public class ComponentManager: ObservedObject { @Published var rows: [any RowProtocol] = [] func updateState(_ newState: any RowProtocolData, id: String) { guard let index = rows.firstIndex(where: { $0.id == id }) else { return } rows[index].updateState(newState) } func getState(id: String) -> any RowProtocolData? { guard let index = rows.firstIndex(where: { $0.id == id }) else { return nil } return rows[index].state } } The RowProtocol is defined as follows: public protocol RowStateProtocol {} public protocol RowProtocol: Identifiable { associatedtype State: RowStateProtocol associatedtype RowView: View var id: String { get } var state: State { get } func updateState(_ newState: State) @MainActor @ViewBuilder func renderRow() -> RowView } extension RowProtocol { func updateState(_ newState: any RowProtocolData) { guard let newState = newState as? State else { return } self.updateState(newState) } } Then in Component View, I need to render the rows based on the underlying type of the row, this where the renderRow() comes in: struct ComponentView: View { @ObservedObject var manager: ComponentManager var body: some View { List { ForEach(manager.rows, id: \.id) { row in HStack { // This HStack prevent List from initing all rows due to AnyView. AnyView(row.renderRow()) } } } } } The row views will be accepting binding to the state of the row and update their state, let says we have a TextRow and a ToggleRow: struct TextRow: RowProtocol { var id: String var state: TextRowState func updateState(_ newState: TextRowState) { self.state = newState } } struct ToggleRow: RowProtocol { var id: String var state: ToggleRowState func updateState(_ newState: ToggleRowState) { self.state = newState } } In this, offcourse we cannot create an binding directly to the state of the row, since the state are through the manager and the row data won't have access to the manager. So I created an property wrapped that use the closures passed by the manager into environment to create the binding and an view that will give the binding to the content view: extenstion EnvironmentValues { @Entry internal var getState: (String) -> any RowStateProtocol? @Entry internal var updateState: (any RowStateProtocol, String) -> Void } @propertyWrapper struct RowStateBinding<State: RowStateProtocol & Equatable>: DynamicProperty { @Environment(\.getState) private var getState @Environment(\.updateState) private var updateState private let id: String init(id: String) { self.id = id } var wrappedValue: State { get { getState(id) as! State } nonmutating set { if wrappedValue != newValue { // only update for an new change, since set can be triggered for any number of reasons. updateState(newValue, id) } } } var projectedValue: Binding<State> { Binding( get: { self.wrappedValue }, set: { newValue in self.wrappedValue = newValue } ) } } struct RowStateBindingView<Content: View, State: RowStateProtocol & Equatable>: View { @RowStateBinding<State> private var state: State private let content: (Binding<State>) -> Content init(id: String, @ViewBuilder content: @escaping (Binding<State>) -> Content) { self._state = RowStateBinding(id: id) self.content = content } var body: some View { content($state) } } and in the renderRows: struct TextRowView: View { @Binding var text: TextRowState var body: some View { TextField("Enter text", text: $text.text) } } extension TextRow { func renderRow() -> some View { RowStateBindingView(id: id) { state in TextField("Enter text", text: state.text) } } } struct ToggleRowView: View { @Binding var state: ToggleRowState var body: some View { Toggle("Toggle", isOn: $state.isOn) } } extension ToggleRow { func renderRow() -> some View { RowStateBindingView(id: id) { state in Toggle("Toggle", isOn: state.isOn) } } } This way, I can adopt any view as an row view and most importantly, the view can be completely independent of the manager and used as an standalone view. Also clients of the library can create their own custom rows by just conforming to the RowProtocol and creating the view for it, without worrying about how the state management works. The manager will handle all the state updates. I prefer using stucts over classes for rows and states, since its easier to manage state updates. What do you think about this approach? Do you see any potential issues with this? Is there a better way to achieve this?
Replies
0
Boosts
0
Views
233
Activity
Jun ’26
Dynamic Property inplace of onChange, task.
In the recent SwiftUI Group Lab, they mentioned using Dynamic Property instead of onChange, How to do it? Could it used as an actual property type instead of just using in combination with @propertyWrapper
Replies
0
Boosts
1
Views
214
Activity
Jun ’26
UIView wrapper around a View
I couldn't decide whether to post this question here or in SwiftUI Q&A as there's a lot of overlaps. We're trying to create something similar to UIViewRepresentable for UIKit. This might not work for complicated cases where the View has many pieces but as long as it works for simple cases, we're happy. The only problem right now is figuring out the correct height. Currently, the height anchor is assigned to CGFloat.greatestFiniteMagnitude, which works but when inspecting the layout in View Hierarchy, it appears the wrapped view is getting stretched all the way down. Also, sometimes View Hierarchy isn't able to draw the wrapped View and I'm unsure if it's a problem of View Hierarchy or our implementation. final public class SwiftUIConfigurationContainerView<T: View>: UIView { private var contentView: UIView? public override var intrinsicContentSize: CGSize { contentView?.intrinsicContentSize ?? super.intrinsicContentSize } private var preferredContentSize: CGSize? public init(@ViewBuilder _ content: @escaping () -> T) { super.init(frame: .zero) setUpContentView(content) } @available(*, unavailable) required init?(coder: NSCoder) { return nil } private func setUpContentView(_ content: @escaping () -> T) { let contentView = UIHostingConfiguration { [weak self] in VStack(spacing: .zero) { content() .onGeometryChange(for: CGSize.self, of: \.size) { size in self?.preferredContentSize = size self?.invalidateIntrinsicContentSize() } .frame(maxWidth: .infinity, alignment: .center) Spacer(minLength: .zero) } } .minSize(width: .zero, height: .zero) .margins(.all, .zero) .makeContentView() self.contentView = contentView addSubview(contentView) contentView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ contentView.leadingAnchor.constraint(equalTo: leadingAnchor), contentView.trailingAnchor.constraint(equalTo: trailingAnchor), contentView.topAnchor.constraint(equalTo: topAnchor), contentView.heightAnchor.constraint(equalToConstant: CGFloat.greatestFiniteMagnitude), ]) } }
Replies
0
Boosts
0
Views
388
Activity
Jun ’26
How to detect backspace in SwiftUI TextField without falling back to UIViewRepresentable?
I'm building a multi-box PIN/OTP input in SwiftUI. In UIKit, I used UITextFieldDelegate to detect backspace presses on an empty field to move focus backward. SwiftUI’s .onChange(of: text) only triggers when text is actually deleted, completely missing backspaces on an already empty field. Is there a pure SwiftUI way to handle this now, or are we still forced to wrap UITextField via UIViewRepresentable?
Replies
1
Boosts
0
Views
264
Activity
Jun ’26
about presentationDetents modifier
How do I make the sheet occupy the full screen width and bottom when I customize the height of the sheet using presentationDetents?
Replies
1
Boosts
0
Views
197
Activity
Jun ’26
@State changes in Xcode 27 are causing variable definitions spanning multiple lines to produce unexpected compiler errors.
On Xcode 27, the compiler incorrectly errors when a @State variable definition is placed on multiple lines. The code compiles without any issues on Xcode 26 and is valid Swift. The issue is fixed if the var definition is placed on a single line. The following code produces issues: @State internal var bodyText = "Hi" However, the code below works: @State internal var bodyText = "Hi" The issue is reproducible in any new project with a simple view: import SwiftUI import Playgrounds @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State internal var bodyText = "Hi" var body: some View { Text(bodyText) .padding() } } #Preview { ContentView() } The expected behavior is for valid Swift code to not trigger compiler error. Filed FB23044343
Replies
1
Boosts
0
Views
463
Activity
Jun ’26
Xcode 27: SwiftUI Preview with SwiftData doesn't work
Overview When a project contains SwiftData and the Preview uses a in memory database, SwiftUI preview doesn't show the data Have a look at the ContentView preview Environment Xcode 27.0 beta (27A5194q) 26.5.1 (25F80) Feedback FB23041713 Please can you have a look at the feedback, it also has a sample project and screenshot
Replies
1
Boosts
0
Views
528
Activity
Jun ’26
Reorderable with Xcode previews
I was playing around with the brand-new reorderable API and couldn't get it to work within previews. Is there a specific way to get previews to work with reorderable, or do I need to compile every time? I was also curious if there will be an addition to the Array generic struct, as it seems like the solution there currently is is just an extension, although the way it's being promoted makes it seem like it is built into the type.
Replies
2
Boosts
0
Views
289
Activity
Jun ’26
Is there a way to change the default scroll edge effect?
It seems like the automatic edge effect defaults to hard in iOS 27 and soft on iOS 26. Designing for both of these is actually quite difficult - especially since hard edge effects don't work with pinned views in LazyVStack. Is there a way to set the global default to soft for an app?
Replies
1
Boosts
0
Views
592
Activity
Jun ’26
tvOS SwiftUI App Bugfixes
Hi :-) I need some advice to fix the following issues in SwiftUI. I don't have the source code myself, but I'd like to help the programmer fix the problem quickly. So I'm looking for a few lines of Example-Code that I can show these Code-Lines to help resolve this quickly. 1. "Jumping shadow" when swiping => The Shadow under the Genre.Buttons jumps when you swipe through them. 2. Liquid Glass Flicker => The Liquid Glass EDGE on a poster or on the buttons flickers (abruptly disappear) when switching from one page to another Can someone help me? Bets regards, Christian :)
Replies
0
Boosts
0
Views
309
Activity
Jun ’26
How to present a View above everything in SwiftUI?
Hello, I'm trying to present an app overlay (like an HUD) that should appear on top of everything (the app UI could be the root content view or a modal presented from the content view or a modal over a modal presented from the content view, etc.). If I use a ZStack for example, the issue is that the view is not visible if the ZStack is presenting a modal for example. In UIKit, I think we can use instantiate another UIWindow to show content above the top window of the app (what a native alert does if I'm not wrong). What would be the equivalent in SwiftUI? How could I create this? Thanks, Axel
Replies
2
Boosts
0
Views
236
Activity
Jun ’26
Wrong position of searchable component on first render
Hey all, I found a weird behaviour with the searchable component. I created a custom bottom nav bar (because I have custom design in my app) to switch between screens. On one screen I display a List component with the searchable component. Whenever I enter the search screen the first time, the searchable component is displayed at the bottom. This is wrong. It should be displayed at the top under the navigationTitle. When I enter the screen a second time, everything is correct. This behaviour can be reproduced on all iOS 26 versions on the simulator and on a physical device with debug and release build. On iOS 18 everything works fine. Steps to reproduce: Cold start of the app Click on Search TabBarIcon (searchable wrong location) Click on Home TabBarIcon Click on Search TabBarIcon (searchable correct location) Simple code example: import SwiftUI struct ContentView: View { @State var selectedTab: Page = Page.main var body: some View { NavigationStack { ZStack { VStack { switch selectedTab { case .main: MainView() case .search: SearchView() } } VStack { Spacer() VStack(spacing: 0) { HStack(spacing: 0) { TabBarIcon(iconName: "house", selected: selectedTab == .main, displayName: "Home") .onTapGesture { selectedTab = .main } TabBarIcon(iconName: "magnifyingglass", selected: selectedTab == .search, displayName: "Search") .onTapGesture { selectedTab = .search } } .frame(maxWidth: .infinity) .frame(height: 55) .background(Color.gray) } .ignoresSafeArea(.all, edges: .bottom) } } } } } struct TabBarIcon: View { let iconName: String let selected: Bool let displayName: String var body: some View { ZStack { VStack { Image(systemName: iconName) .resizable() .renderingMode(.template) .aspectRatio(contentMode: .fit) .foregroundColor(Color.black) .frame(width: 22, height: 22) Text(displayName) .font(Font.system(size: 10)) } } .frame(maxWidth: .infinity) } } enum Page { case main case search } struct MainView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() .navigationTitle("Home") } } struct SearchView: View { @State private var searchText = "" let items = [ "Apple", "Banana", "Pear", "Strawberry", "Orange", "Peach", "Grape", "Mango" ] var filteredItems: [String] { if searchText.isEmpty { return items } else { return items.filter { $0.localizedCaseInsensitiveContains(searchText) } } } var body: some View { List(filteredItems, id: \.self) { item in Text(item) } .navigationTitle("Fruits") .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search") } }
Replies
5
Boosts
0
Views
493
Activity
Jun ’26