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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

SwiftUI: AlignmentGuide in Overlay not working when in if block
Scenario A SwiftUI view has an overlay with alignment: .top, the content uses .alignmentGuide(.top) {} to adjust the placement. Issue When the content of the overlay is in an if-block, the alignment guide is not adjusted. Example code The example shows 2 views. Not working example, where the content is an if-block. Working example, where the content is not in an if-block Screenshot: https://github.com/simonnickel/FB15248296-SwiftUIAlignmentGuideInOverlayConditional/blob/main/screenshot.png Tested on - Xcode Version 16.0 RC (16A242) on iOS 18.0 Code // Not working .overlay(alignment: .top) { if true { // This line causes .alignmentGuide() to fail Text("Test") .alignmentGuide(.top, computeValue: { dimension in dimension[.bottom] }) } } // Working .overlay(alignment: .top) { Text("Test") .alignmentGuide(.top, computeValue: { dimension in dimension[.bottom] }) } Also created a Feedback: FB15248296 Example Project is here: https://github.com/simonnickel/FB15248296-SwiftUIAlignmentGuideInOverlayConditional/tree/main
0
0
71
1w
Issues with List selection in Sequoia (SwiftUI)
In one of my applications I use several List views with Sections. After upgrading to Sequoia I faced the issue, that after selecting an item, the List suddenly scrolls to a different position. Sometimes the selection even gets out of the view, but in every case a double click just went to the wrong item. At one list I found out, that the issue could be solved after changing the data source. I used a computed property, what seems to be a stupid idea. After changing this it now works. Unfortunately there is another List, where this didn't bring the solution. And unfortunately, I cannot reproduce the issue in a code example. One guess of mine is, that it could be related to the fact, that the rows have different heights (because in some are two lines of text and in some are three). And it seems to happen only in very long lists. It worked perfectly in Sonoma. Does anyone face the same issue?
3
0
96
1w
Disable Swipe in SwiftUI NavigationView
I am using SwiftUI NavigationView to navigate. I cant find how can i disable swipe from the leftmost part of the screen for navigation bar. In tried this way , but it doesn't work for me: struct DisableSwipeBackGesture: ViewModifier { func body(content: Content) -> some View { content .background(DisableBackSwipeGestureView()) } } struct DisableBackSwipeGestureView: UIViewControllerRepresentable { typealias UIViewControllerType = DisableSwipeBackViewController func makeUIViewController(context: Context) -> DisableSwipeBackViewController { DisableSwipeBackViewController() } func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} func makeCoordinator() -> Coordinator { return Coordinator() } class Coordinator: NSObject, UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return false } } } final class DisableSwipeBackViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if let navigationController = self.navigationController { if let interactivePopGestureRecognizer = navigationController.interactivePopGestureRecognizer { interactivePopGestureRecognizer.delegate = self interactivePopGestureRecognizer.isEnabled = false } } } } extension DisableSwipeBackViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return false } } extension View { func disableSwipeBackGesture() -> some View { self.modifier(DisableSwipeBackGesture()) } } Is there a way to disable this feature?
0
0
53
1w
Disable SwiftUI NavigationView Swipe
I am using SwiftUI NavigationView to navigate. I cant find how can i disable swipe from the leftmost part of the screen for navigation bar. Im tried this way , but it doesn't work for me: struct DisableBackSwipeGestureView: UIViewControllerRepresentable { typealias UIViewControllerType = UINavigationController func makeUIViewController(context: Context) -> UINavigationController { DisableSwipeBackViewController().navigationController ?? UINavigationController() } func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} func makeCoordinator() -> Coordinator { return Coordinator() } class Coordinator: NSObject, UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return false } } } final class DisableSwipeBackViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if let navigationController = self.navigationController { if let interactivePopGestureRecognizer = navigationController.interactivePopGestureRecognizer { interactivePopGestureRecognizer.delegate = self interactivePopGestureRecognizer.isEnabled = false } } } } extension DisableSwipeBackViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return false } } extension View { func disableSwipeBackGesture() -> some View { self.modifier(DisableSwipeBackGesture()) } } Is there a way to disable this feature in swiftui?
0
0
41
1w
iOS 18 navigationBar color scheme not working
Hello, I'm encountering an issue with toolbarColorScheme in iOS 18. In a simple example, toolbarColorScheme works fine when triggered in onAppear. However, after navigating to a different view (e.g., following a link, such as link 234), and then returning, the toolbarColorScheme seems to be ignored. Could anyone help me resolve this issue? struct TestNavigationBarColor: View { var body: some View { NavigationStack { List { Text("123") NavigationLink(value: 1) { Text("234") } } .toolbarColorScheme(.dark, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar) .navigationTitle("Title1") .navigationDestination(for: Int.self) {_ in List { Text("Nested screen") } .navigationTitle("Title2") } } } }
1
0
139
1w
NavigationSplitView issues in iOS 18 and 18.1
Hello, In our current project we are using NavigationSplitView in the following way: var body: some View { NavigationSplitView( sidebar: { ListView() }, detail: { DetailsView() } ) .navigationBarHidden(true) .navigationSplitViewStyle(.automatic) .introspectSplitViewController { splitViewController in splitViewController.preferredDisplayMode = .oneOverSecondary splitViewController.maximumPrimaryColumnWidth = 500 splitViewController.preferredPrimaryColumnWidthFraction = 1 } } } And in iPhone the DetailsView() is pushed using the navigationDestination modifier: .navigationDestination(isPresented: $isShowingDetailsScreen) { DetailsView() .navigationBarHidden(true) } where isShowingDetailsScreen is updated through a button click: Button() { self.isShowingDetailsScreen = true } This works perfectly in iOS versions prior to 18. However starting from this version the button click no longer presents the view desired. Below is what happening in the latest iOS versions: iOS 18: This mechanism is broken altogether, it does not work at all. iOS 18.1: This mechanism is partially broken, when clicking on the button the DetailsView is not presented, however since the page also contains other reactive views, any time one of them is changed through a state change after clicking on that button, the DetailsView is presented. Does anyone faced an issue like this with the new iOS and if so is there any workaround for now? Because this seems to be a bug caused by changes in SwiftUI and shouldn't persist for long.
2
0
137
1w
After interacting with a button in the live activity, the Control widget and home screen widget did not update.
I have a button on a live activity, and I want to end the live activity and update the Control Center widgets and home screen widgets after clicking this button. So, in the perform() method of the button's LiveActivityIntent, I called the methods ControlCenter.shared.reloadAllControls() and WidgetCenter.shared.reloadAllTimelines(), but they didn't work. Home screen widgets and Control Center widgets do not refresh, resulting in a poor user experience.
1
0
100
1w
.searchable bug with new navigationTransitions
When using the new .navigationTransition feature, when using .searchable at the same time result in the search bar disappearing when dismissing the view you've trasition to, has anyone else experienced this or found any workarounds? Here is an example that make the issue always occur. @State private var searchText: String = "" @Namespace private var namespace let things: [String] = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirdteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"] var body: some View { NavigationStack { ScrollView { LazyVStack(spacing: 20) { ForEach(things, id: \.self) { thing in NavigationLink(){ SwiftUIView(thing: thing, name: namespace) }label: { Text(thing) } .matchedTransitionSource(id: thing, in: namespace) } } } .searchable(text: $searchText) .navigationTitle("My List") .navigationBarTitleDisplayMode(.inline) } } } struct SwiftUIView: View { var thing: String var name: Namespace.ID var body: some View { Text(thing) .navigationTransition(.zoom(sourceID: thing, in: name)) } } After running the code you end up with this: And after clicking an element and dismissing it your get this:
2
0
119
1w
Help understanding `SwiftUI.App` identity lifecycle and need for `SwiftUI.State`?
Hi! I have a stateful object that should be created in my app entry point and delivered through my component graph: @main @MainActor struct MyApp : App { @State private var myAppState = MyAppState() var body: some Scene { ... } } The MyApp is a struct value type… in a SwiftUI world that seems to imply it could "go away" and be recreated as the system sees appropriate. We see this with view components all the time (hence the State wrapper to help preserve our instance across the lifecycle of our identity)… but I'm wondering if this State wrapper is even necessary with an App entry point. Could this struct ever go away? Would there be any legit reasons that this struct should go away and recreate over one SwiftUI app lifecycle (other than terminating the app and starting a whole new process of course)? And what lifecycle is the SwiftUI.State tied to in this example? In a view component our SwiftUI.State is tied to our component identity. In this example… we are tied to app component identity? Is there ever going to be multiple legit app component identities live in the same process? I'm thinking I could just go ahead and keep using State as a best practice… but is this just overkill or is there a real best practice lurking under here? Any more ideas about that? Thanks!
2
0
127
1w
Issue with SwiftUI NavigationStack, Searchable Modifier, and Returning to Root View
I'm facing an issue with SwiftUI's NavigationStack when using the searchable modifier. Everything works as expected when navigating between views, but if I use the search bar to filter a list and then tap on a filtered result, I can navigate to the next view. However, in the subsequent view, my "Set and Return to Root" button, which is supposed to call popToRoot(), does not work. Here's the setup: Structure: RootView: Contains a list with items 1-7. ActivityView: Contains a list of activities that can be filtered with the searchable modifier. SettingView: Contains a button labeled "Set and Return to Root" that calls popToRoot() to navigate back to the root view. RootView struct RootView: View { @EnvironmentObject var navManager: NavigationStateManager var body: some View { NavigationStack(path: $navManager.selectionPath) { List(1...7, id: \.self) { item in Button("Element \(item)") { // Navigate to ActivityView with an example string navManager.selectionPath.append(NavigationTarget.activity) } } .navigationTitle("Root View") .navigationDestination(for: NavigationTarget.self) { destination in switch destination { case .activity: ActivityView() case .settings: SettingsView() } } } } } ActivityView struct ActivityView: View { @EnvironmentObject var navManager: NavigationStateManager let activities = ["Running", "Swimming", "Cycling", "Hiking", "Yoga", "Weightlifting", "Boxing"] @State private var searchText = "" var filteredActivities: [String] { if searchText.isEmpty { return activities } else { return activities.filter { $0.localizedCaseInsensitiveContains(searchText) } } } var body: some View { List { ForEach(filteredActivities, id: \.self) { activity in NavigationLink( destination: SettingsView(), // Navigiere zur SettingsView label: { HStack { Text(activity) .padding() Spacer() } } ) } } .navigationTitle("Choose Activity") .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search Activities") } } SettingView struct SettingsView: View { @EnvironmentObject var navManager: NavigationStateManager var body: some View { VStack { Text("Settings") .font(.largeTitle) .padding() Button("Set and Return to Root") { // Pop to the root view when the button is pressed navManager.popToRoot() } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(10) } .navigationTitle("Settings") } } NavigationStateManager // Define enum globally at the top enum NavigationTarget { case activity case settings } class NavigationStateManager: ObservableObject { @Published var selectionPath = NavigationPath() func popToRoot() { selectionPath = NavigationPath() } func popView() { selectionPath.removeLast() } } Problem When I search in the ActivityView and tap on a filtered result, I successfully navigate to the SettingView. However, in this view, pressing the "Set and Return to Root" button does not trigger the navigation back to RootView, even though popToRoot() is being called. This issue only occurs when using the search bar and filtering results. If I navigate without using the search bar, the button works as expected. Question Why is the popToRoot() function failing after a search operation, and how can I ensure that I can return to the root view after filtering the list? Any insights or suggestions would be greatly appreciated!
3
0
188
1w
TabView more tab has double navigation bar when there's more than five tabs
When there are more than 5 tabs in TabView, the tabs from the 5th and on get put in the "More" tab as a list. But when each tab has its own NavigationStack, the tabs in "More" would have double navigation bars. The expected behavior is there should be only one navigation bar, and NavigationStack for tabs in "More" should be collapsed with navigation for the "More" tab itself. Minimal reproducible case: Run the code below as an app Navigate to "More" tab Navigate to "Tab 5" or "Tab 6" You can see there are two navigation bars stacked on top of each other struct Item: Identifiable { let name: String var id: String { name } } @main struct TestApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { let items = [ Item(name: "Tab 1"), Item(name: "Tab 2"), Item(name: "Tab 3"), Item(name: "Tab 4"), Item(name: "Tab 5"), Item(name: "Tab 6"), ] var body: some View { TabView { ForEach(items) { item in NavigationStack { List { Text(item.name) }.navigationTitle(item.name) }.tabItem { Label(item.name, systemImage: "person") } } } } } Before iOS 18, I can get around this issue by making my own "More" tab. But now with the expectation that user can re-arrange the tabs and all tabs would show up in the sidebar, the "make my own more tab" approach no longer work very well.
3
1
135
1w
Switching from Dark to Light mode does not update the background of `TabView` in SwiftUI,
Since iOS 18 I have noticed a strange issue which happens to the TabView in SwiftUI when you switch from Dark to Light mode. With this code: import SwiftUI struct ContentView: View { var body: some View { TabView { List { ForEach(0..<100, id: \.self) { index in Text("Row: \(index)") } }.tabItem { Image(systemName: "house") Text("Home") } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } The TabBar does not switch colours when going from dark to light, it work correctly when going from light to dark. Here is a video of iOS 18 with the issue: Here is a video of iOS 17.5 with same code and no issue: On real device it looks (better), the color does update but with delay. I have submitted a feedback bug report, but in the meanwhile has anyone been back to resolve this?
1
1
108
1w
users Widgets disappear!!! Xcode 16
Some users have reported that the app's widgets have disappeared after we updated to the latest Xcode for iOS 18 development. They are unable to find our app in the widget search, which prevents them from re-adding the widget. We were unable to reproduce this issue on our own devices during testing. Could this be a system bug? Have others encountered a similar issue?
7
4
268
1w
onTapGesture in Menu or not working
Hi, after update to Swift6 and iOS 18 my code is not working anymore. This is code from documentation with onTapGesture (instead of primaryAction) and it's not working. OnTapGesture is not starting when user click. Menu { Button(action: {}) { Label("Add to Reading List", systemImage: "eyeglasses") } Button(action: {}) { Label("Add Bookmarks for All Tabs", systemImage: "book") } Button(action: {}) { Label("Show All Bookmarks", systemImage: "books.vertical") } } label: { Label("Add Bookmark", systemImage: "book") } onTapGesture: { print(" Print on tap gesture") } primaryAction isn't working either. I mean, primary action works but menu is not showing inside buttons. Menu { Button(action: {}) { Label("Add to Reading List", systemImage: "eyeglasses") } Button(action: {}) { Label("Add Bookmarks for All Tabs", systemImage: "book") } Button(action: {}) { Label("Show All Bookmarks", systemImage: "books.vertical") } } label: { Label("Add Bookmark", systemImage: "book") } primaryAction: { print("") } I also tried to overlay the menu, no effect. ZStack { Menu { Button(action: {}) { Label("Add to Reading List", systemImage: "eyeglasses") } Button(action: {}) { Label("Add Bookmarks for All Tabs", systemImage: "book") } Button(action: {}) { Label("Show All Bookmarks", systemImage: "books.vertical") } } label: { Label("Add Bookmark", systemImage: "book") } Color.clear .contentShape(Rectangle()) .onTapGesture { print("Tap gesture recognized") } } Please help. How to start action when user is clicking on menu?
2
2
208
1w
External Display with SwiftUI in 2024
What is current best-practice for supporting an external display in a SwiftUI iOS app in 2024? (I'm only interested in iOS 17 and/or iOS 18) The only docs I found require abandoning the SwiftUI App structure and "switching back to a full UIKit App Delegate". Is this still the only option? Are there any complete examples on how to accomplish this? Also is testing external displays with Simulator at all reliable? All experiences I read about say that it never works. Thanks in advance.
0
0
101
1w
SwiftUI ScrollView performance in macOS 15
There seems to be a performance issue when scrolling using the track pad with SwiftUI scroll views in macOS 15. This issue is NOT present in macOS 14. When using the track pad the scrolling is not smooth, but "stutters". However scrolling using the scroll bars is very smooth. The "stuttering" is worse if the SwiftUI ScrollView is in the detail view of a NavigationSplitView. The problem is not noticeable in scroll views with a small number views, but when the more views inside the scroll view, the more prominent the problem becomes. I have a simple example app that illustrates the problem here (the example app is a simplification of my app Yammixer): https://github.com/danwaltin/SwiftUIScrollViewPerformance When running this example app on macOS 14 (Sonoma) on an Intel i7 Mac book pro from 2019 the scrolling is "buttery smooth". But on macOS 15 (Sequoia) on my Apple Silicon M1 Mac book pro the issue is very obvious. When using Instruments I see that on macOS 15 "flame graph" shows that 85% of the execution time is in a "_hitTestForEvent" method. If the test app does not use NavigationSplitView about 70% of execution time is in the _hitTestForEvent method.
3
3
111
1w
Using TextField:text:selection crashes on macOS
I am trying out the new TextField selection ability on macOS but it crashes in various different ways with extremely large stack traces. Looks like it is getting into re-entrant function calls. A similar problem is described on the SwiftUI forums with no responses yet. Here is my simple example struct ContentView: View { @State private var text: String = "" @State private var selection: TextSelection? var body: some View { TextField("Message", text: $text, selection: $selection) .padding() } } Setting text to a value like "Hallo World" causes an instant crash as soon as you start typing in the TextField. Setting text empty (as in example above) lets you edit the text but as it crashes as soon as you commit it (press enter). Any workarounds or fixes?
1
0
85
1w
iOS 18 - Toolbar keyboard placement within TabView, NavigationSplitView
Hello, After a fair amount of time of trial and error, I have seemingly discovered a bug in iOS 18 with .toolBar with placement:. keyboard) Feedback: FB15205988 Xcode Version: 16.0 (16A242d) iOS Version: 18.0 (22A3351) I'd appreciate help to see if I'm missing something here. What's happening? When using .toolBar with (placement: .keyboard), within a NavigationSplitView detail:, encompassed in a TabView, the .toolBar view does not appear above the keyboard. Within the code, the usage of .toolBar is within ShakeDetail.swift. When commenting out the TabView within ShakeTabView.swift, or running on iOS 17.5, the .toolbar appears. Would greatly appreciate help if someone knows a workaround, or a misunderstanding here of course! Code Shake.swift import Foundation import SwiftUI struct Shake: Equatable, Identifiable, Hashable { var name: String let id = UUID() static var example = Shake(name: "Banana") static var many: [Shake] { return [ Shake(name: "Apple"), Shake(name: "Banana"), Shake(name: "Cherry"), Shake(name: "Berry"), ] } } ShakeDetail.swift import SwiftUI struct ShakeDetail: View { @State var shake: Shake = Shake(name: "") var body: some View { List { TextField("dsf", text: $shake.name, prompt: Text("Enter your favorite shake")) } .scrollDismissesKeyboard(.interactively) .toolbar { ToolbarItem(placement: .keyboard) { HStack(alignment: .center) { Text(shake.name) .font(.title3) .foregroundColor(.red) } } } .toolbarColorScheme(.dark, for: .navigationBar) .toolbarBackground( Color.purple, for: .navigationBar ) .toolbarBackground(.visible, for: .navigationBar) } } #Preview { ShakeDetail() } ShakeListView.swift struct ShakeListView: View { @Binding var shakes: [Shake] @Binding var selectedShake: Shake? var body: some View { List(selection: $selectedShake) { ForEach(shakes) { shake in NavigationLink(value: shake) { Text(shake.name) .font(.system(.title2, design: .rounded)) .foregroundStyle(.primary) } } } .navigationTitle("Shakes") } } #Preview { @Previewable @State var shakes: [Shake] = Shake.many @Previewable @State var selectedShake: Shake? ZStack { ShakeListView(shakes: $shakes, selectedShake: $selectedShake) } } ShakeSplitView.swift import SwiftUI import OSLog public struct ShakeSplitView: View { @State var selectedShake: Shake? @State var shakes = Shake.many @State private var columnVisibility = NavigationSplitViewVisibility.doubleColumn public init(isShowingFavorites: Bool = false, columnVisibility: SwiftUI.NavigationSplitViewVisibility = NavigationSplitViewVisibility.doubleColumn) { self.columnVisibility = columnVisibility } public var body: some View { NavigationSplitView(columnVisibility: $columnVisibility) { ShakeListView(shakes: $shakes, selectedShake: $selectedShake) } detail: { if let selectedShake { // Add shake detail ShakeDetail(shake: selectedShake) } else { Label("Please select a shake", systemImage: "arrow.backward.circle") .foregroundColor(.purple) .font(.system(.title2, design: .rounded)) } } .navigationSplitViewStyle(.balanced) } } struct FormulaSplitView_Previews: PreviewProvider { static var previews: some View { ShakeSplitView() } } ShakeTabView.swift import SwiftUI struct ShakeTabView: View { var body: some View { /* TabView breaks the ToolbarItem(placement: .keyboard) */ TabView { ShakeSplitView() .tabItem { Image(systemName: "carrot.fill") Text("Shakes") } } } } #Preview { ShakeTabView() }
4
0
270
1w
what's wrong with `ToolbarItemGroup(placement: .keyboard)` inside `TavView`?
Why is there inconstancy of appearing the keyboard tool bar Item with tab view? Try to go to second tab and focus the field. Sometimes it does not appear (in my more complex project it does not appear >90% times). import SwiftUI struct MainTabView: View { var body: some View { TabView { FirstTabView() .tabItem { Label("Tab 1", systemImage: "house") } SecondTabView() .tabItem { Label("Tab 2", systemImage: "star") } } } } struct FirstTabView: View { @State private var text = "" var body: some View { NavigationStack { VStack { TextField("Enter something 1", text: $text) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() } .toolbar { ToolbarItemGroup(placement: .keyboard) { Button("Done") { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } } } } } struct SecondTabView: View { @State private var text = "" var body: some View { NavigationStack { VStack { TextField("Enter something 2", text: $text) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() } .toolbar { ToolbarItemGroup(placement: .keyboard) { Button("Done") { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } } } } } #Preview { MainTabView() }
0
1
108
1w