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

SwiftUI Documentation

Posts under SwiftUI subtopic

Post

Replies

Boosts

Views

Activity

SwiftData with shared and private containers
I was hoping for an update of SwiftData which adopted the use of shared and public CloudKit containers, in the same way it does for the private CloudKit container. So firstly, a big request to any Apple devs reading, for this to be a thing! Secondly, what would be a sensible way of adding a shared container in CloudKit to an existing app that is already using SwiftData? Would it be possible to use the new DataStore method to manage CloudKit syncing with a public or shared container?
11
18
3.4k
Jun ’24
Xcode 16: SwiftUI plain Button & UIImageView not working
It looks like Xcode 16 has changed this behaviour so I'm not sure if this is a bug or not. When a SwiftUI Button wraps a UIImageView and the button style is .plain the button doesn't work without setting isUserInteractionEnabled. struct ContentView: View { var body: some View { Button { print("Hello World!") } label: { UITestImage() } .buttonStyle(.plain) } } struct UITestImage: UIViewRepresentable { func makeUIView(context: Context) -> UIImageView { let view = UIImageView() // view.isUserInteractionEnabled = true // Fix view.image = UIImage(systemName: "plus") view.contentMode = .scaleAspectFit view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) view.setContentCompressionResistancePriority(.defaultLow, for: .vertical) view.layoutMargins = .zero return view } public func updateUIView(_ uiView: UIImageView, context: Context) {} } This feels unexpected, is this a bug?
2
1
922
Jun ’24
SwiftUI Popover clips in iOS18
When you try to present medium height popover from the bottom of iPhone view then popover is clipped in iOS18 but works in old devices Sample code Button("Show Popover") { showPopover.toggle() } .popover( isPresented: $showPopover, arrowDirection: arrowDirection ) { conent } Result
5
0
1.8k
Jun ’24
Multi Polygons MapKit
Is MultiPolygon overlay support going to be integrated with SwiftUI? I have made a post on here previously without a reply :( Any suggestions on how to display multi-polygons within MapKit for SwiftUI(https://developer.apple.com/documentation/mapkit/mappolygon)? At the moment it is not supported and only supported by MapKit for UIKit(https://developer.apple.com/documentation/mapkit/mkmultipolygon).
4
1
1.2k
Jun ’24
Slider .rotationEffect broken in MacOS 14.5
In a SwiftUI app for MacOS, vertical sliders that I'd created using a rotationEffect of 90° disappeared when I upgraded to Sonoma 14.5 (23F79). With rotations less than 90°, the slider is still visible, but its button is enlarged, growing in size as the rotation angle approaches 90°. Note that the sliders still work, even when rotated by 90° and invisible! The screenshot and code below demonstrates the problem, which did not exist in MacOS 14.2.1 struct ContentView: View { @State var speed = CGFloat(1) var body: some View { HStack { let angle: [Double] = [0, 45, 80, 85, 90] ZStack { ForEach(0...4, id: \.self) { i in ZStack () { Rectangle() Slider(value: $speed, in: 0...10 ) } .frame(width: 100, height: 10) .rotationEffect(.degrees(angle[i])) .offset(x: CGFloat(i * 100) - 180) } } } .padding() .frame(width: 600, height: 200) } } #Preview { ContentView() }
Topic: UI Frameworks SubTopic: SwiftUI
6
1
821
Jun ’24
Live Activity compact timers
The Human Interface Guidelines for Live Activities provide several examples of compact presentations that have a timer counting down formatted like "3min" or "3m", similar to the timers in the Clock app. Such examples can be found in this Stack Overflow question: https://stackoverflow.com/questions/77551496/is-it-possible-to-make-an-only-minutes-1m-countdown-in-a-live-activity A Timer initialized with init(timerInterval:pauseTime:countsDown:showsHours:) has provided a live countdown timer in widgets and live activities, but the formatting is limited. And since live activities come with limitations that prevent us from using Timers, there's no real way to implement this kind of thing ourselves. What is Apple's official guidance for implementing this kind of timer for the compact presentation?
5
2
2.6k
Jun ’24
No containerBackground content on Widget in iOS 18 tinted home screen style
The widget I have create for iOS 17 uses the containerBackground to display an image in the background. This works fine. But when I set the home screen to the iOS 18 tinted option the background disappears. I want the background to stay because it contains an image of that is meaningful to the user. I use the following code: @ViewBuilder var body: some View { if let memory = entry.memory, let uiImage = memory.image { Group { if entry.showCaption { memoryBody(with: memory) } else { Color.white.opacity(0.0000000001) } } .foregroundStyle(.white) .widgetBackground( Image(uiImage: uiImage) .resizable() .scaledToFill() ) } else if let memory = entry.memory { memoryBody(with: memory) .widgetBackground(Color.gray) } else { noMemoryBody() } } extension View { func widgetBackground(_ backgroundView: some View) -> some View { if #available(iOSApplicationExtension 17.0, *) { return containerBackground(for: .widget) { backgroundView } } else { return background(backgroundView) } } }
4
1
2.1k
Jun ’24
SwiftUI Previews broken on local Swift Package with dependencies
I have a project with two local packages One client package with an interface and some models with dynamic type in the Package.Swift One feature package with the UI and a dependency to the client package When I try to preview a view that is not using any models or code from the client package, it loads just fine e.g. a view that is just a container to display things like a card But when I tried to preview any other view that actually uses models from the client package, it just fails the first few lines of the preview error display LinkDylibError: Failed to build <filename>.swift Linking failed: linker command failed with exit code 1 (use -v to see invocation) ld: warning: search path '/Applications/Xcode-15.4.0.app/Contents/SharedFrameworks-iphonesimulator' not found Undefined symbols for architecture arm64: Also, I'm using Xcode 15.4 and iOS 17 as the min version
6
1
1.9k
Jun ’24
Combining Matched Geometry with New Zoom Navigation Transitions in iOS 18
With the introduction of the new matchedTransitionSource from iOS 18, we can apply a zoom transition in the navigation view using .navigationTransition(.zoom) This works well for zoom animations. However, when I try to apply a matched geometry effect to views that are similar in the source and destination views, the zoom transition works, but those views don't transition seamlessly as they do with a matched geometry effect. Is it possible to still use matched geometry for subviews of the source and destination views along with the new navigationTransition? Here’s a little demo that reproduces this behaviour: struct ContentView: View { let colors: [[Color]] = [ [.red, .blue, .green], [.yellow, .purple, .brown], [.cyan, .gray] ] @Namespace() var namespace var body: some View { NavigationStack { Grid(horizontalSpacing: 50, verticalSpacing: 50) { ForEach(colors, id: \.hashValue) { rowColors in GridRow { ForEach(rowColors, id: \.self) { color in NavigationLink { DetailView(color: color, namespace: namespace) .navigationTransition( .zoom( sourceID: color, in: namespace ) ) .edgesIgnoringSafeArea(.all) } label: { ZStack { RoundedRectangle(cornerRadius: 5) .foregroundStyle(color) .frame(width: 48, height: 48) Image(systemName: "star.fill") .foregroundStyle(Material.bar) .matchedGeometryEffect(id: color, in: namespace, properties: .frame, isSource: false) } } .matchedTransitionSource(id: color, in: namespace) } } } } } } } struct DetailView: View { var color: Color let namespace: Namespace.ID var body: some View { ZStack { color Image(systemName: "star.fill") .resizable() .foregroundStyle(Material.bar) .matchedGeometryEffect(id: color, in: namespace, properties: .frame, isSource: false) .frame(width: 100, height: 100) } .navigationBarHidden(false) } } #Preview { ContentView() }
1
4
1.1k
Jun ’24
Title Bar Height Impact on Window Size in SwiftUI on macOS
In a SwiftUI macOS application, when removing the title bar by setting window.titleVisibility to .hidden and window.titlebarAppearsTransparent to true, the title bar space is still accounted for in the window height. This results in a delta (red area) in the height of the window that cannot be ignored by usual SwiftUI view modifiers like .edgesIgnoringSafeArea(.top). My actual view is the blue area. I want to have the view starting in the top safeArea and the window to be the exact size of my view. I am struggling to achieve this. I have also tried with window.styleMask.insert(.fullSizeContentView) to no effect. Can I get some help? 🙂 Here is my source code to reproduce this behavior: windowApp.swift @main struct windowApp: App { @NSApplicationDelegateAdaptor private var appDelegate: AppDelegate var body: some Scene { WindowGroup { ContentView() .edgesIgnoringSafeArea(.top) .background(.red) .border(.red) } } } class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { if let window = NSApplication.shared.windows.first { window.titleVisibility = .hidden window.titlebarAppearsTransparent = true window.styleMask.insert(.fullSizeContentView) } } } ContentView.swift import SwiftUI struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .frame(minWidth: 400, minHeight: 200) .background(.blue) } }
Topic: UI Frameworks SubTopic: SwiftUI
1
1
940
Jun ’24
Location Permission Popup Not Appearing in SwiftUI App
Hello everyone, I'm working on a SwiftUI app that requires location services, and I've implemented a LocationManager class to handle location updates and permissions. However, I'm facing an issue where the location permission popup does not appear when the app is launched. Here is my current implementation: LocationManager.swift: import CoreLocation import SwiftUI class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() @Published var userLocation: CLLocation? @Published var isAuthorized = false @Published var authorizationStatus: CLAuthorizationStatus = .notDetermined override init() { super.init() locationManager.delegate = self checkAuthorizationStatus() } func startLocationUpdates() { locationManager.startUpdatingLocation() } func stopLocationUpdates() { locationManager.stopUpdatingLocation() } func requestLocationAuthorization() { print("Requesting location authorization") DispatchQueue.main.async { self.locationManager.requestWhenInUseAuthorization() } } private func checkAuthorizationStatus() { print("Checking authorization status") authorizationStatus = locationManager.authorizationStatus print("Initial authorization status: \(authorizationStatus.rawValue)") handleAuthorizationStatus(authorizationStatus) } func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { print("Authorization status changed") authorizationStatus = manager.authorizationStatus print("New authorization status: \(authorizationStatus.rawValue)") handleAuthorizationStatus(authorizationStatus) } private func handleAuthorizationStatus(_ status: CLAuthorizationStatus) { switch status { case .authorizedAlways, .authorizedWhenInUse: DispatchQueue.main.async { self.isAuthorized = true self.startLocationUpdates() } case .notDetermined: requestLocationAuthorization() case .denied, .restricted: DispatchQueue.main.async { self.isAuthorized = false self.stopLocationUpdates() print("Location access denied or restricted") } @unknown default: DispatchQueue.main.async { self.isAuthorized = false self.stopLocationUpdates() } } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { DispatchQueue.main.async { self.userLocation = locations.last } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("Location manager error: \(error.localizedDescription)") } } MapzinApp.swift: @main struct MapzinApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @StateObject private var locationManager = LocationManager() var body: some Scene { WindowGroup { Group { if locationManager.authorizationStatus == .notDetermined { Text("Determining location authorization status...") } else if locationManager.isAuthorized { CoordinatorView() .environmentObject(locationManager) } else { Text("Location access is required to use this app. Please enable it in Settings.") } } } } } Log input: Checking authorization status Initial authorization status: 0 Requesting location authorization Authorization status changed New authorization status: 0 Requesting location authorization Despite calling requestWhenInUseAuthorization() when the authorization status is .notDetermined, the permission popup never appears. Here are the specific steps I have taken: Checked the Info.plist to ensure the necessary keys for location usage are present: NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Verified that the app's target settings include location services capabilities. Tested on a real device to ensure it's not a simulator issue. I'm not sure what I might be missing. Any advice or suggestions to resolve this issue would be greatly appreciated. Thank you!
2
0
2.2k
Jun ’24
Crash After Presenting SwiftUI Alert
I’m seeing a crash in production for a small percentage of users, and have narrowed it down based on logging to happening as or very shortly after an alert is presented using SwiftUI. This seems to be isolated to iOS 17.5.1, but since it’s a low-volume crash I can’t be sure there aren’t other affected versions. What can I understand from the crash report? Here’s a simplified version of the code which presents the alert, which seems so simple I can’t understand why it would crash. And following that is the crash trace. // View (simplified) @MainActor public struct MyView: View { @ObservedObject var model: MyViewModel public init(model: MyViewModel) { self.model = model } public var body: some View { myViewContent .overlay(clearAlert) } var clearAlert: some View { EmptyView().alert( "Are You Sure?", isPresented: $model.isClearAlertVisible, actions: { Button("Keep", role: .cancel) { model.clearAlertKeepButtonWasPressed() } Button("Delete", role: .destructive) { model.clearAlertDeleteButtonWasPressed() } }, message: { Text("This cannot be undone.") } ) } } // Model (simplified) @MainActor public final class MyViewModel: ObservableObject { @Published var isClearAlertVisible = false func clearButtonWasPressed() { isClearAlertVisible = true } func clearAlertKeepButtonWasPressed() { // No-op. } func clearAlertDeleteButtonWasPressed() { // Calls other code. } } Incident Identifier: 36D05FF3-C64E-4327-8589-D8951C8BAFC4 Distributor ID: com.apple.AppStore Hardware Model: iPhone13,2 Process: My App [379] Path: /private/var/containers/Bundle/Application/B589E780-96B2-4A5F-8FCD-8B34F2024595/My App.app/My App Identifier: com.me.MyApp Version: 1.0 (1) AppStoreTools: 15F31e AppVariant: 1:iPhone13,2:15 Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: com.me.MyApp [583] Date/Time: 2024-06-21 20:09:20.9767 -0500 Launch Time: 2024-06-20 18:41:01.7542 -0500 OS Version: iPhone OS 17.5.1 (21F90) Release Type: User Baseband Version: 4.50.06 Report Version: 104 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001a69998c0 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [379] Triggered by Thread: 0 Kernel Triage: VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter Thread 0 name: Thread 0 Crashed: 0 libswiftCore.dylib 0x00000001a69998c0 _assertionFailure(_:_:file:line:flags:) + 264 (AssertCommon.swift:144) 1 AttributeGraph 0x00000001d0cd61a4 Attribute.init<A>(body:value:flags:update:) + 352 (Attribute.swift:473) 2 SwiftUI 0x00000001ac034054 closure #1 in Attribute.init<A>(_:) + 128 (<compiler-generated>:0) 3 SwiftUI 0x00000001ac033cac partial apply for closure #1 in Attribute.init<A>(_:) + 32 (<compiler-generated>:0) 4 libswiftCore.dylib 0x00000001a6ad0450 withUnsafePointer<A, B>(to:_:) + 28 (LifetimeManager.swift:128) 5 SwiftUI 0x00000001ad624d14 closure #2 in UIKitDialogBridge.startTrackingUpdates(actions:) + 268 (UIKitDialogBridge.swift:370) 6 SwiftUI 0x00000001ad624ae0 UIKitDialogBridge.startTrackingUpdates(actions:) + 248 (UIKitDialogBridge.swift:369) 7 SwiftUI 0x00000001ad6250cc closure #4 in UIKitDialogBridge.showNewAlert(_:id:) + 72 (UIKitDialogBridge.swift:471) 8 SwiftUI 0x00000001abfdd050 thunk for @escaping @callee_guaranteed () -> () + 36 (:-1) 9 UIKitCore 0x00000001aa5722e4 -[UIPresentationController transitionDidFinish:] + 1096 (UIPresentationController.m:651) 10 UIKitCore 0x00000001aa571d88 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke.114 + 320 (UIPresentationController.m:1390) 11 UIKitCore 0x00000001aa5cb9ac -[_UIViewControllerTransitionContext completeTransition:] + 116 (UIViewControllerTransitioning.m:304) 12 UIKitCore 0x00000001aa34a91c __UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__ + 36 (UIView.m:16396) 13 UIKitCore 0x00000001aa34a800 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 624 (UIView.m:16429) 14 UIKitCore 0x00000001aa349518 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 436 (UIView.m:0) 15 UIKitCore 0x00000001aa356b14 -[UIViewAnimationState animationDidStop:finished:] + 192 (UIView.m:2400) 16 UIKitCore 0x00000001aa356b84 -[UIViewAnimationState animationDidStop:finished:] + 304 (UIView.m:2422) 17 QuartzCore 0x00000001a96f8c50 run_animation_callbacks(void*) + 132 (CALayer.mm:7714) 18 libdispatch.dylib 0x00000001aff61dd4 _dispatch_client_callout + 20 (object.m:576) 19 libdispatch.dylib 0x00000001aff705a4 _dispatch_main_queue_drain + 988 (queue.c:7898) 20 libdispatch.dylib 0x00000001aff701b8 _dispatch_main_queue_callback_4CF + 44 (queue.c:8058) 21 CoreFoundation 0x00000001a808f710 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 (CFRunLoop.c:1780) 22 CoreFoundation 0x00000001a808c914 __CFRunLoopRun + 1996 (CFRunLoop.c:3149) 23 CoreFoundation 0x00000001a808bcd8 CFRunLoopRunSpecific + 608 (CFRunLoop.c:3420) 24 GraphicsServices 0x00000001ecf3c1a8 GSEventRunModal + 164 (GSEvent.c:2196) 25 UIKitCore 0x00000001aa6c490c -[UIApplication _run] + 888 (UIApplication.m:3713) 26 UIKitCore 0x00000001aa7789d0 UIApplicationMain + 340 (UIApplication.m:5303) 27 SwiftUI 0x00000001ac27c148 closure #1 in KitRendererCommon(_:) + 168 (UIKitApp.swift:51) 28 SwiftUI 0x00000001ac228714 runApp<A>(_:) + 152 (UIKitApp.swift:14) 29 SwiftUI 0x00000001ac2344d0 static App.main() + 132 (App.swift:114) 30 My App 0x00000001001e7bfc static MyApp.$main() + 52 (MyApp.swift:0) 31 My App 0x00000001001e7bfc main + 64 32 dyld 0x00000001cb73de4c start + 2240 (dyldMain.cpp:1298)
3
0
946
Jun ’24
SwiftUI: listSectionSeparator not working on macOS
Hi, When I use 'listSectionSeparator' on hide the section separator on a List 'section', it works as expected on iOS, but doesn't have any effect on macOS. Is that a known issue? Are there any workarounds for this? Here's a basic reproducible example: import SwiftUI struct TestItem: Identifiable, Hashable { let id = UUID() let itemValue: Int var itemString: String { get { return "test \(itemValue)" } } } struct TestListSelection: View { let testArray = [TestItem(itemValue: 1), TestItem(itemValue: 2), TestItem(itemValue: 3), TestItem(itemValue: 4)] @State private var selectedItem: TestItem? = nil var body: some View { List (selection: $selectedItem) { Section("Header") { ForEach (testArray, id: \.self) { item in Button { print("main row tapped for \(item.itemValue)") } label: { HStack { Text(item.itemString) Spacer() Button("Tap me") { print("button tapped") } .buttonStyle(.borderless) } } .buttonStyle(.plain) } } .listSectionSeparator(.hidden) // has no effect on macOS Section("2nd Header") { ForEach (testArray, id: \.self) { item in Text(item.itemString) } } .listSectionSeparator(.hidden) // has no effect on macOS } .listStyle(.plain) } } #Preview { TestListSelection() }
1
1
530
Jun ’24
macOS SwiftUI Sheets are no longer resizable (Xcode 16 beta2)
For whatever reason SwiftUI sheets don't seem to be resizable anymore. The exact same code/project produces resizable Sheets in XCode 15.4 but unresizable ones with Swift included in Xcode 16 beta 2. Tried explicitly providing .fixedSize(horizontal false, vertical: false) everywhere humanly possible hoping for a fix but sheets are still stuck at an awkward size (turns out be the minWidth/minHeight if I provide in .frame).
6
1
2.5k
Jun ’24
Vertical ScrollView Height and Paging Offset Issues in SwiftUI
Hi everyone, I'm currently working on an iOS app using SwiftUI, and I'm facing an issue with a vertical ScrollView. My goal is to have the ScrollView take up all the safe area space plus the top inset (with the bottom inset being an ultra-thin material) and enable paging behavior. However, I'm encountering two problems: The initial height of the ScrollView is too high (dragging the view (even without changing the page) adjusts the size). The paging offset of the ScrollView is incorrect (page views are not aligned). I’ve tried many things and combinations in desperation, including padding, safeAreaPadding, contentMargins, frame, fixedSize, containerRelativeFrame with callback, custom layout, and others, but nothing seems to work. If by any chance someone can help me find a solution, I’d greatly appreciate it. I suspect there are issues with the height defined by the ScrollView when some safe areas are ignored, leading to strange behavior when trying to set the height. It's challenging to explain everything in a simple post, so if someone from the SwiftUI team could look into this potential bug, that would be incredibly helpful. Thank you! import SwiftUI struct ScrollViewIssue: View { @State private var items: [(String, Color)] = [ ("One", .blue), ("Two", .green), ("Three", .red), ("Four", .purple) ] var body: some View { ZStack(alignment: .top) { ScrollView(.vertical) { VStack(spacing: 0) { ForEach(items, id: \.0) { item in ItemView(text: item.0, color: item.1) .containerRelativeFrame([.horizontal, .vertical]) } } } .printViewSize(id: "ScrollView") .scrollTargetBehavior(.paging) .ignoresSafeArea(edges: .top) VStack { Text("Title") .foregroundStyle(Color.white) .padding() .frame(maxWidth: .infinity) .background(Color.black.opacity(0.2)) Spacer() } } .printViewSize(id: "ZStack") .safeAreaInset(edge: .bottom) { Rectangle() .frame(width: .infinity, height: 0) .overlay(.ultraThinMaterial) } } } struct ItemView: View { let text: String let color: Color var body: some View { ZStack { RoundedRectangle(cornerRadius: 20) .fill(color.opacity(0.2)) .overlay( color, in: RoundedRectangle(cornerRadius: 20) .inset(by: 10 / 2) .stroke(lineWidth: 10) ) Text(text) } .printViewSize(id: "item") } } struct ViewSizeKey: PreferenceKey { static var defaultValue = CGSize() static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() } } extension View { func printViewSize(id: String) -> some View { background( GeometryReader { proxy in Color.clear .preference(key: ViewSizeKey.self, value: proxy.size) } .onPreferenceChange(ViewSizeKey.self) { value in print("\(id) size:\(value)") } ) } } #Preview { ScrollViewIssue() }
3
1
3.2k
Jul ’24
Why can't SwiftUI state be changed in the middle of view updates?
I have arrived at a certain architectural solution for my SwiftUI code which is helped by, in certain situations, modifying the state while the body is being evaluated. Of course, I am always open to realizing that a given solution may be creating difficulties precisely because it is fundamentally ill-advised. However, in this post I won't attempt to explain the details of my architecture or justify my reasoning regarding wanting to change the state in the middle of a view update. I just want to ask, why exactly is it prohibited? Is it not rather like normal recursion, which can of course produce infinite loops if done wrong but which is perfectly logically sound as long as the recursing function eventually stabilizes?
Topic: UI Frameworks SubTopic: SwiftUI
7
0
1k
Jul ’24
Not receive onDisappear event on the first WindowGroup
Hi, I'm working on visionOS and find I can't get onDisappear event just on the first window after app launch. It comes like that: WindowGroup(id:"WindowA"){ MyView() .onDisappear(){ print("WindowA disappear") } } WindowGroup(id:"WindowB"){ MyView() .onDisappear(){ print("WindowB disappear") } } WindowGroup(id:"WindowC"){ MyView() .onDisappear(){ print("WindowC disappear") } } When the app first launch, it will open WindowA automatically And then I open WindowB and WindowC programatically. Then I tap the close button on window bar below window. If I close WindowB/WindowC, I can receive onDisappear event If I close WindowA, I can't receive onDisappear event If I reopen WindowA after it is closed and then close it again by tap the close button below window, I can receive onDisappear event Is there any logic difference for the first window on app launch? How can I get onDisappear Event for it. I'm using Xcode 16 beta 2
5
0
1k
Jul ’24
SwiftUI : NavigationStack in new iOS 18 TabView pushes twice when path in parameter
Hello, With iOS 18, when NavigationStack is in new TabView, with path parameter containing current navigation state is set, the navigation destination view is pushed twice. See below with example that pushes twice on iOS 18 but is correct on iOS 17 @MainActor class NavigationModel: ObservableObject { static let shared = NavigationModel() @Published var selectedTab: String @Published var homePath: [Route] @Published var testPath: [Route] } struct ContentView: View { @StateObject private var navigationModel: NavigationModel = NavigationModel.shared var body: some View { TabView(selection: $navigationModel.selectedTab){ HomeView() .tabItem { Label("Home", systemImage: "house") } .tag("home") TestView() .tabItem { Label("Test", systemImage: "circle") } .tag("test") } } } struct HomeView: View { @StateObject private var navigationModel: NavigationModel = NavigationModel.shared var body: some View { NavigationStack(path: $navigationModel.homePath){ VStack{ Text("home") NavigationLink(value: Route.test1("test1")){ Text("Go to test1") } } .navigationDestination(for: Route.self){ route in NavigationModelBuilder.findFinalDestination(route:route) } } } } I don't what causes the issue because it works well on iOS 16 and iOS 17. I think the path is somehow reset but I don't why (maybe by the TabView ?) Note that the bug only occurs with TabView. Don't really know if it is a TabView bug or if it is on my side. I filed a feedback with sample project FB14312064
34
11
6.8k
Jul ’24
WidgetBundle with ControlWidget does not work on iOS 17
I'm trying to add a ControlWidget to my WidgetBundle like this: struct MyWidgets: WidgetBundle { var body: some Widget { if #available(iOSApplicationExtension 18.0, *) { LauncherControl() } MyLiveActivityWidget() HomeScreenWidget() LockScreenWidget() } This works exactly as expected on iOS 18. However on iOS 17 my app seems to have no widgets at all. The workaround described here (https://www.avanderlee.com/swiftui/variable-widgetbundle-configuration/) does not work either since WidgetBundleBuilder.buildBlock does not accept ControlWidget as an argument. What is the correct way to include a Control widget conditionally on iOS 18?
5
1
3.4k
Jul ’24