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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

Live Activity activityBackgroundTint not using dark mode colour variant
I have defined a colour in the asset catalog of my widget extension. I am using this widget extension for my live activity. This colour has both an ‘Any’ and ‘Dark’ appearance. I am using this colour in the activityBackgroundTint modifier for my main live activity view (the ActivityPreviewViewKind is content, visible on the Lock Screen). In light mode, this works as expected, but in dark mode, the background colour is still the light mode variant. The content within the view changes according to whether the system is in light or dark mode, but the background does not. I want to avoid using just the background modifier instead of activityBackgroundTint, as this does not colour the ‘Allow Live Activities from …’ and ‘Clear’ sections, which is undesirable. I have also tried reading colorScheme from the environment and choosing the light or dark mode colour variant accordingly, but this workaround also doesn’t completely work. If you keep changing from light and dark mode (via the Settings app, not the control centre, for whatever reason), the background colour actually becomes the opposite of the expected value in this case. Is there a workaround that can help me achieve what I want, or am I simply doing something wrong? I have filed a bug report under FB15148099
1
1
127
1w
CKAsset URLs discarded after backgrounding app in iOS 18
My app uses a temporary singleton to store CKRecords for user profiles, to prevent repeated fetching of profile pics & display usernames during a user's session. Since iOS 18, after leaving the app in the background for an unspecified period of time & reopening it, the app has started to discard the CKAssets in those 'cached' records. The records are still there, & the custom fields such as the display username string is still accessible. However the profile pic assets aren't? This is the code that is displaying the profile picture, could this be something to do with some changes to how CKAssets are given file urls? if postOwnerRecord != nil, let imageAsset = postOwnerRecord!.object(forKey: "profilePicture") as? CKAsset, let photoData = NSData(contentsOf:imageAsset.fileURL!) { if let uiImage = UIImage(data: photoData as Data) { let imageToUse = Image(uiImage: uiImage) Image(uiImage: imageToUse) } } Expected behavior: CKAssets should persist when resuming the app from the background. Actual behavior: CKAssets are discarded when reopening the app, but custom fields are still accessible. Question: Is this related to iOS 18, or am I mishandling how CKAssets are cached or their file URLs? Is there a better approach to caching these assets across app sessions? Any pointers or changes would be appreciated. I've reviewed iOS 18 release notes but didn't find any clear references to changes with CKAsset handling. Any ideas?
1
0
141
1w
TextFields inside a List lose focus after each character
My problem: I tap in one of the TextFields defined below and try to type. After typing a single character, the cursor disappears from the TextField and I need to tap in the field again to enter the next character. I have the following code: @Observable final class Species { . . . public var list: [String] . . . } struct SpeciesCapture: View { @State private var species = Species() @State var trainingList: [String] = [] var body: some View { NavigationStack { VStack(alignment: .leading) { HStack { Text("some text") Spacer() Button("Add") { trainingList.append("") } } List { ForEach($trainingList, id: \.self) { $animal in TextField("Animal", text: $animal) .textCase(.lowercase) } } } .onAppear { trainingList = species.list . . . } . . . // etc. } } } It appears that I am continually losing focus. How do I fix this problem? Xcode 16.0 targeting iOS 18. The behavior appears in both Preview and the Simulator. (Haven't tried it on a physical device).
1
0
83
2w
Prevent dismissal of sheet in SwiftUI
I'd like to emulate the behavior of UIViewController.isModalInPresentation in SwiftUI. In my first attempt, I defined the following view: struct ModalView<Content: View>: UIViewControllerRepresentable { 		var content: () -> Content 		func makeUIViewController(context: Context) -> UIHostingController<Content> { 				let controller = UIHostingController(rootView: content()) 				controller.isModalInPresentation = true 				return controller 		} 		func updateUIViewController(_ imagePickerController: UIHostingController<Content>, context: Context) {} } From my main app view, I then present the ModalView as a sheet: struct ContentView: View { 		@State 		var presentSheet: Bool = true 		var body: some View { 				Text("Hello, world!") 						.sheet(isPresented: $presentSheet) { 								ModalView { 										Text("Sheet") 								} 						} 		} } But the user is still able to dismiss the ModalView by swiping down. I would expect this sheet to be non-dismissible. Is anything like this supposed to work? If not, is there some other way to prevent the dismissal of a sheet in SwiftUI? The closest workaround I've found is to apply .highPriorityGesture(DragGesture()) to the content of the sheet, but swiping down with two fingers still works.
5
1
8.2k
Jun ’20
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.
4
4
137
2w
Can't find or decode availabilityDetailedInfo warning when start editing textField
Whenever I start editing TextField or while editing TextField, Xcode shows this worning, and takes a few seconds to show the keyboard. There is no 'availabilityDetailedInfo' in my source code, and I could not find similar errors on the internet. Can't find or decode availabilityDetailedInfo unavailableReasonsHelper: Failed to get or decode availabilityDetailedInfo Can't find or decode reasons unavailableReasonsHelper: Failed to get or decode unavailable reasons as well Can't find or decode availabilityDetailedInfo unavailableReasonsHelper: Failed to get or decode availabilityDetailedInfo Can't find or decode reasons unavailableReasonsHelper: Failed to get or decode unavailable reasons as well
2
2
189
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
63
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
49
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
209
2w
Error when clicking on TextField : CLIENT ERROR: TUINSRemoteViewController does not override -viewServiceDidTerminateWithError: and thus cannot react to catastrophic errors beyond logging them
Hello, I face an error everytime I want to interact with a TextField. The XCode debug area is showing : CLIENT ERROR: TUINSRemoteViewController does not override -viewServiceDidTerminateWithError: and thus cannot react to catastrophic errors beyond logging them There is no crash, and the text field is working fine. I am developing for MacOS using a macbook pro Intel from 2019 with Sonoma 14.5 and Xcode 15.4 and I think that I noticed since the release of Sonoma. I was not particularly concerned by it but I noticed that interacting with the textField was leading to severe hang in my app, and micro-hang in the test app and I am wondering is these two issues could be related. The message is easy to reproduce. Just create a new Project/Application/App using SwiftUI and add a TextField to the ContentView. When you start app, click or double click on the text field, enter a message and press enter. import SwiftUI struct ContentView: View { @State var value: String = "" var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") TextField(text: $value, label: { Text("Test") } ) } .padding() } } Did you notice the same thing ? How I could solve it ? Note : I already posted the problem on Swift forums but it was close because related to SwiftUI https://forums.swift.org/t/error-when-clicking-on-textfield-client-error-tuinsremoteviewcontroller-does-not-override-viewservicedidterminatewitherror-and-thus-cannot-react-to-catastrophic-errors-beyond-logging-them/72134/1 Thank you
20
10
3.4k
Jun ’24
ControlWidget can't open APP
My custom control widget is show up and I can set it to Lock Screen, but it doesn't launch my app when I clicked it. any problem? in A.swift file, code like below: @available(iOS 18.0, *) struct LockScreenAppLaunchWidget: ControlWidget { var body: some ControlWidgetConfiguration { StaticControlConfiguration(kind: "abc") { ControlWidgetButton(action: LaunchAppIntent()) { // <-- HERE Label("Something", systemImage: "arrow.up") } } .displayName("Open app") } } @available(iOS 18, *) struct LaunchAppIntent: AppIntent { static var title: LocalizedStringResource = "ABC" static var description: IntentDescription? = "abcd" static var openAppWhenRun: Bool = true @MainActor func perform() async throws -> some IntentResult & OpensIntent { return .result() } }
2
1
168
2w
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
139
1w
The behavior of onDrag and onDrop in iOS 18 is different from previous versions.
I am developing an app that supports iOS 15 and later. Up until iOS 17, the behavior of onDrag and onDrop was as follows: The item is moved by holding it and dragging it to the onDrop area. When the item is dropped in the onDrop area, the logic is executed, and simultaneously, the item disappears immediately. However, in iOS 18 the item remains for about 0.5 to 1.0 seconds before disappearing, even though there is no logic in the onDrop. Is this the expected behavior, or is it a bug?"
3
0
155
2w
SignInWithApple / AuthenticationServices fails SwiftUI
Xcode 15.2, iOS 17.2 I have a piece of code that displays videos. It has been working for at least 6 months. Suddenly only the first video played. The following videos would only play audio with the video being frozen at the first frame. I noticed that SwiftUI would start to instantiate multiple instances of my player observable class instead of just one. After chasing the problem for most of a day I found that if I completely removed every piece of code referencing AuthenticationServices then everything would work fine again. Even if I add the following piece of code which is not used or called in any way. Then SwiftUI will start to act weird. func configure(_ request: ASAuthorizationAppleIDRequest) { request.requestedScopes = [.fullName, .email] } If I comment out request.requestedScopes = [.fullName, .email] everything works fine. The SignInWithApple is configured and works fine if I enable the code. Any suggestions on how to solve or any work arounds would be highly appreciated.
1
0
569
Feb ’24
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
99
2w
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
123
2w
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
148
2w
Live Activities Random Loading Spinner
Somewhat rarely, but often enough to be a problem, our live activities will entirely lock up with a frozen progress spinner and a dimmed appearance. We cannot figure out what this spinner means nor how to avoid it as it is not documented anywhere. No logs appear in Xcode nor in Console.app. We have more frequent updates enabled and are sending an update maybe once every 2 minutes, nothing that should cause us to exceed our quota. We cannot reproduce in a debugger Can we get some guidance on how to avoid this?
3
0
251
3w