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

Posts under SwiftUI tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Loading object on NSItemProvider is delayed until drop exit
I have drag-and-drop functionality in the macOS app built with SwiftUI. Since macOS 15 there is an issue with it, because as I found out, the completion block of loadObject method on NSItemProvider is not called until dropExited delegate method is called (see simplified code example below). It causes very strange behavior in my app, for one of the most important features, and I am looking for a way to fix it as soon as possible. Is anyone seeing the same issue? I saw there was a bug with drag and drop on iOS 18, which seems to be fixed in 18.1. Anyone from Apple can say anything about this change in behaviour? @Observable // Because it is injected via environment. final class DragAndDropDelegate<T: Codable>: DropDelegate { func dropEntered(info: DropInfo) { // Is called as expected. guard let itemProvider = info.itemProviders(for: [UTType.data]).first else { return } itemProvider.loadObject(ofClass: DraggableObject<T>.self) { [weak self] (object, error) in // This is only called after dropExited delegate method is called !!! // Before macOS 15.0 it is called quickly after the loadObject method invokation. asyncOnMainThread { guard let self, let draggableObject = object as? DraggableObject<T> else { return } self.onEnter?(draggableObject.object, info.location) } } } func dropExited(info: DropInfo) { // Is called as expected. } }
4
0
164
2w
How would you make a View that magnifies the View(s) beneath it?
I need a magnifying glass function for one of my SwiftUI Views, but can't find a way to implement it as needed. I found a Youtube video where the author renders the view twice, overlaying the second over the first, then scaling and masking it to create the illusion of magnification, but this is expensive and doesn't work in many cases where more complex views are presented (e.g. a LazyVGrid). I've also explored continually capturing partial screenshots and scaling them up to create the illusion of magnification, but there's no straightforward way to achieve this with SwiftUI without getting into the messiness of UIViewRepresentables. Any help would be greatly appreciated
2
0
147
3w
Is it intended for onchange to work with let properties?
Hi all, by chance, we introduced code similar to the following in the body of one of our views: struct MyView: View { let myInt: Int var body: some View { EmptyView() // Empty body .onChange(of: myInt) { newValue in … } } } Notice that a simple let of type Int is used here, rather than State or something similar. While it works and onChange is actually triggered when views are rebuilt, I’d like to clarify a few things: Is this behavior actually expected and reliable, or is it a gray area and can be changed in the future? If it is expected, can this be made clearer in the documentation? If it is a gray area, can the documentation be improved to address it? Thanks!
1
1
149
3w
Tapping Take Photo reloads Image Playground sheet on iOS
I integrated the image playground sheet in my app, however when I select Take Photo on the iOS version of my app it just reloads the sheet. After several attempts I get the below error message. This issue doesn’t occur on the macOS version of my app, where it first requests camera permission before allowing me to take the photo. I’m not sure if this is happening because I don’t request the camera permission anywhere in my app. My app doesn’t use the camera at all apart from the Take Photo feature which is part of the image playground sheet. Feedback ID: FB15591786
0
0
185
3w
Swift MacOS crash at start when using it on a Mac which is set to french language
A Swift MacOS works with no problem on Intel or ARM Macs (from 11, BigSur to 15, Sequoia) but recently I learned that is crashes when launched on a Mac which language is set to French. I'm not saying this setting is causing the issue, but is the most obvious difference observed compared to many other Macs where the App runs with no problem. The crash occurred in a MacOS intel. See excerpts from crash report below: Process: MySwiftAPP [626] Path: /Volumes/VOLUME/*/MySwiftAPP.app/Contents/MacOS/MySwiftAPP Identifier: Myinfo.MYSwiftAPP Version: X.Y.01 (1) Code Type: X86-64 (Native) Parent Process: launchd [1] User ID: 501 Date/Time: 2021-01-05 01:47:12.0578 +0100 OS Version: macOS 12.2.1 (21D62) Report Version: 12 Bridge OS Version: 3.0 (14Y910) Anonymous UUID: 3579800E-84CC-15C4-2981-320ECF2E1400 Time Awake Since Boot: 62 seconds System Integrity Protection: enabled Crashed Thread: 0 Dispatch queue: com.apple.main-thread Exception Type: EXC_BAD_INSTRUCTION (SIGILL) Exception Codes: 0x0000000000000001, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4 Terminating Process: exc handler [626] Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 MySwiftAPP 0x10c6df5bb 0x10c61d000 + 796091 1 MySwiftAPP 0x10c6be4dc 0x10c61d000 + 660700 2 SwiftUI 0x7ff919a8ff0e closure #1 in AppearanceActionModifier.MergedBox.update() + 72 3 SwiftUI 0x7ff9193d2047 thunk for @escaping @callee_guaranteed () -> () + 12 4 SwiftUI 0x7ff919a91012 partial apply for thunk for @escaping @callee_guaranteed () -> () + 17 5 SwiftUI 0x7ff919bbc028 closure #1 in ViewRendererHost.render(interval:updateDisplayList:) + 2414 6 SwiftUI 0x7ff919ba9fbe ViewRendererHost.render(interval:updateDisplayList:) + 359 7 SwiftUI 0x7ff919c04d56 closure #1 in NSHostingView.layout() + 126 8 SwiftUI 0x7ff919c0dce7 partial apply for thunk for @callee_guaranteed (@guaranteed NSAnimationContext) -> () + 17 9 SwiftUI 0x7ff919c023fd thunk for @escaping @callee_guaranteed (@guaranteed NSAnimationContext) -> () + 36 10 AppKit 0x7ff8113fa152 +[NSAnimationContext runAnimationGroup:] + 55 11 SwiftUI 0x7ff919c04c8a NSHostingView.layout() + 287 12 SwiftUI 0x7ff919c0508a @objc NSHostingView.layout() + 21 13 AppKit 0x7ff811435d7f NSViewLayout + 564 14 AppKit 0x7ff811435851 -[NSView layoutSubtreeWithOldSize:] + 352 15 AppKit 0x7ff811434d68 -[NSView layoutSubtreeIfNeededAndAllowTemporaryEngine:] + 1041 16 AppKit 0x7ff811677f22 +[NSWindow windowWithContentViewController:] + 57 17 SwiftUI 0x7ff9199cd634 specialized WindowStyle.makeWindow(:) + 42 18 SwiftUI 0x7ff919b6c724 AnyWindowStyleStorage.makeWindow(:) + 26 19 SwiftUI 0x7ff91974a736 AppWindowsController.makeWindowController(:restorationID:environment:) + 2314 20 SwiftUI 0x7ff91974887d AppWindowsController.makeMainWindow(info:) + 66 21 SwiftUI 0x7ff9197487c7 AppWindowsController.makeMainWindow() + 424 22 SwiftUI 0x7ff919748067 AppWindowsController.showInitialMainWindow() + 82 23 SwiftUI 0x7ff9194e0c3e AppDelegate.applicationDidFinishLaunching(:) + 85 24 SwiftUI 0x7ff9194e0dd6 @objc AppDelegate.applicationWillFinishLaunching(_:) + 114 25 CoreFoundation 0x7ff80e9a6f23 CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER + 12 26 CoreFoundation 0x7ff80ea443f9 ___CFXRegistrationPost_block_invoke + 49 27 CoreFoundation 0x7ff80ea44376 _CFXRegistrationPost + 496 28 CoreFoundation 0x7ff80e978836 _CFXNotificationPost + 733 29 Foundation 0x7ff80f7c01be -[NSNotificationCenter postNotificationName:object:userInfo:] + 82 30 AppKit 0x7ff8113e761b -[NSApplication _postDidFinishNotification] + 305 31 AppKit 0x7ff8113e736d -[NSApplication _sendFinishLaunchingNotification] + 208 32 AppKit 0x7ff8113e4f40 -[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] + 541 33 AppKit 0x7ff8113e4b97 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 665 34 Foundation 0x7ff80f7eb194 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 308 35 Foundation 0x7ff80f7eb006 _NSAppleEventManagerGenericHandler + 80 36 AE 0x7ff815043d28 0x7ff815038000 + 48424 37 AE 0x7ff815043592 0x7ff815038000 + 46482 38 AE 0x7ff81503c9c7 aeProcessAppleEvent + 419 39 HIToolbox 0x7ff8175fdc42 AEProcessAppleEvent + 54 40 AppKit 0x7ff8113df222 DPSNextEvent + 2064 41 AppKit 0x7ff8113dd3f4 -[NSApplication(NSEvent) nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1411 42 AppKit 0x7ff8113cf919 -[NSApplication run] + 586 43 AppKit 0x7ff8113a37b7 NSApplicationMain + 816 44 SwiftUI 0x7ff9191dad3f specialized runApp(:) + 161 45 SwiftUI 0x7ff919bf9c84 runApp(:) + 164 46 SwiftUI 0x7ff91970191f static App.main() + 63 47 MySwiftAPP 0x10c6be9ae 0x10c61d000 + 661934 48 dyld 0x1134d64fe start + 462 Thread 1: 0 libsystem_pthread.dylib 0x7ff80e8e5fec start_wqthread + 0 Thread 0 crashed with X86 Thread State (64-bit): rax: 0x0000000200000003 rbx: 0x00007f8db5915210 rcx: 0xfffffffe00000000 rdx: 0x0000000000000003 rdi: 0x00007f8db586b178 rsi: 0x00007ff8518bbf58 rbp: 0x00007ff7b38e0080 rsp: 0x00007ff7b38e0000 r8: 0x0000000000000002 r9: 0x80000000ffffffff r10: 0xfffffffe00000000 r11: 0x0000000000000001 r12: 0x00007f8db586b170 r13: 0x00007f8db586bb40 r14: 0x00007f8db586b290 r15: 0xe800000000000000 rip: 0x000000010c6df5bb rfl: 0x0000000000010297 cr2: 0x00007ff8510288e8 Logical CPU: 0 Error Code: 0x00000000 Trap Number: 6
2
0
156
3w
SwiftData updates in the background are not merged in the main UI context
Hello, SwiftData is not working correctly with Swift Concurrency. And it’s sad after all this time. I personally found a regression. The attached code works perfectly fine on iOS 17.5 but doesn’t work correctly on iOS 18 or iOS 18.1. A model can be updated from the background (Task, Task.detached or ModelActor) and refreshes the UI, but as soon as the same item is updated from the View (fetched via a Query), the next background updates are not reflected anymore in the UI, the UI is not refreshed, the updates are not merged into the main. How to reproduce: Launch the app Tap the plus button in the navigation bar to create a new item Tap on the “Update from Task”, “Update from Detached Task”, “Update from ModelActor” many times Notice the time is updated Tap on the “Update from View” (once or many times) Notice the time is updated Tap again on “Update from Task”, “Update from Detached Task”, “Update from ModelActor” many times Notice that the time is not update anymore Am I doing something wrong? Or is this a bug in iOS 18/18.1? Many other posts talk about issues where updates from background thread are not merged into the main thread. I don’t know if they all are related but it would be nice to have 1/ bug fixed, meaning that if I update an item from a background, it’s reflected in the UI, and 2/ proper documentation on how to use SwiftData with Swift Concurrency (ModelActor). I don’t know if what I’m doing in my buttons is correct or not. Thanks, Axel import SwiftData import SwiftUI @main struct FB_SwiftData_BackgroundApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Item.self) } } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @State private var simpleModelActor: SimpleModelActor! @Query private var items: [Item] var body: some View { NavigationView { VStack { if let firstItem: Item = items.first { Text(firstItem.timestamp, format: Date.FormatStyle(date: .omitted, time: .standard)) .font(.largeTitle) .fontWeight(.heavy) Button("Update from Task") { let modelContainer: ModelContainer = modelContext.container let itemID: Item.ID = firstItem.persistentModelID Task { let context: ModelContext = ModelContext(modelContainer) guard let itemInContext: Item = context.model(for: itemID) as? Item else { return } itemInContext.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000)) try context.save() } } .buttonStyle(.bordered) Button("Update from Detached Task") { let container: ModelContainer = modelContext.container let itemID: Item.ID = firstItem.persistentModelID Task.detached { let context: ModelContext = ModelContext(container) guard let itemInContext: Item = context.model(for: itemID) as? Item else { return } itemInContext.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000)) try context.save() } } .buttonStyle(.bordered) Button("Update from ModelActor") { let container: ModelContainer = modelContext.container let persistentModelID: Item.ID = firstItem.persistentModelID Task.detached { let actor: SimpleModelActor = SimpleModelActor(modelContainer: container) await actor.updateItem(identifier: persistentModelID) } } .buttonStyle(.bordered) Button("Update from ModelActor in State") { let container: ModelContainer = modelContext.container let persistentModelID: Item.ID = firstItem.persistentModelID Task.detached { let actor: SimpleModelActor = SimpleModelActor(modelContainer: container) await MainActor.run { simpleModelActor = actor } await actor.updateItem(identifier: persistentModelID) } } .buttonStyle(.bordered) Divider() .padding(.vertical) Button("Update from View") { firstItem.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000)) } .buttonStyle(.bordered) } else { ContentUnavailableView( "No Data", systemImage: "slash.circle", // 􀕧 description: Text("Tap the plus button in the toolbar") ) } } .toolbar { ToolbarItem(placement: .primaryAction) { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } } private func addItem() { modelContext.insert(Item(timestamp: Date.now)) try? modelContext.save() } } @ModelActor final actor SimpleModelActor { var context: String = "" func updateItem(identifier: Item.ID) { guard let item = self[identifier, as: Item.self] else { return } item.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000)) try! modelContext.save() } } @Model final class Item: Identifiable { var timestamp: Date init(timestamp: Date) { self.timestamp = timestamp } }
0
1
327
4w
Question about .presentationDetents and interactiveDismissDisabled modifiers
I have an app that I'm working on where I'd like to use the .presentationDetents modifier and I need the view to not be dismissed by the user. I'm therefore using the .interactiveDismissDisabled modifier. Unfortunately, that means that the Map on the ContentView can no longer respond to touch gestures. How can I have a similar experience to the Maps app where the underlying Map (or other views) can be interacted with and the user can still be prevented from dismissing the view controlled by the .presentationDetents modifier? SomeView(searchResults: $searchResults, selectedItem: $selectedItem) .presentationDetents([.height(100), .medium]) .presentationDragIndicator(.visible) .interactiveDismissDisabled(true)
2
0
209
4w
Failed to preview SwiftUI app for macOS in Xcode 12.(0, 1, 3, 4).
Hello! SwiftUI preview does not work. I tried different versions of Xcode, deleting the "Developer" folders, clearing the "Build" folder from the project in Xcode, reinstalling Command Line Tools and Developer Tools. I think that the error appeared after I cleaned Xcode with CleanMyMacX, before that the preview worked. -MacBook Pro (15-inch, Mid 2012) -macOS Catalina 10.15.7 -Xcode 12.3 Thanks for the feedback!
1
0
187
4w
VoiceOver issues with LazyVStack in ScrollView
I have a ScrollView which has inside a LazyVStack and multiple rows. On the appearing of the ScrollView, I scroll to row 250. When having the VoiceOver running, after opening the app, the focus is on the navigation title as it should be, than, after swiping right to enter the ScrollView, one would expect the focus to be placed on the first visible row, but this is not the case, it scrolls back to some row and focus on that, than reads it. Here is the code to reproduce it, and if you ask me, this is pretty standard stuff I don't do anything special. import SwiftUI struct ContentView: View { var body: some View { NavigationView { ScrollViewReader { scrollProxy in ScrollView { LazyVStack { ForEach(1...500, id: \.self) { index in NavigationLink(destination: DetailView(row: index)) { Text("Row \(index)") .padding() .frame(maxWidth: .infinity) .background(Color.gray.opacity(0.2)) .cornerRadius(8) .padding(.horizontal) } } } } .onAppear { // Scroll to row 250 when the view appears withAnimation { scrollProxy.scrollTo(250, anchor: .center) } } } .navigationTitle("Rows") } } } struct DetailView: View { let row: Int var body: some View { VStack { Text("Detail for Row \(row)") .font(.largeTitle) .padding() Spacer() } .navigationTitle("Row \(row) Details") } } @main struct ScrollViewExampleApp: App { var body: some Scene { WindowGroup { ContentView() } } }
0
0
140
4w
Are SwiftUI Text views with empty strings optimized out in iOS 18?
A UI test case that checks for the existence of a SwiftUI Text element initialized with an empty string previously reliably passed in iOS 17. In iOS 18 the assertion reliably fails. I searched the iOS 18 developer release notes for anything possibly related to this but didn't find much. I'd like to point to a conclusive change in iOS handling before changing the test permantently. Can anyone confirm that this is indeed a change in iOS 18?
0
3
165
4w
Displaying to-many relationships in CoreData
Any CoreData experts know what could be going on here when trying to display to-many entity type relationship data? On initialisation my model does an fetch request for an entity called Expense, and some prefetching for related entities (to-many type) like this: request.relationshipKeyPathsForPrefetching = ["splits"] I was under the impression that calling a property on one of the related entities should fire the fault (if there is one) and give me the value. Here’s where it starts to go wrong. I have a property in my extension that I use in my detailed view: public var viewExpenseSplits: [ExpenseSplit] { return splits?.allObjects as? [ExpenseSplit] ?? [] } and then a list in my detail view: List(expense.viewExpenseSplits, id: \.self) { split in Text(split.amount ?? "") } Result: What's even more baffling is that I have no problem viewing these splits in the parent view. I thought perhaps I would have more luck passing the viewExpenseSplits through to the detail view instead of trying to access them from the Expense entity itself. Whilst I can print the data out when the view loads, my list still has the same problem. I thought this would be trivial. Can anyone point to me where I'm going wrong? Thanks!
1
0
157
4w
TimelineView corrupts independent animations
Hello. I am here to report a problem. I was investigating the strange behaviour of my text animation, and I've found out that unrelated TimelineView is causing the problem. text is animating on change and there are colors on background (in ZStack) that change using TimelineView. As a result, when the text changes, it twitches, until it fills the whole screen width. If I pause TimelineView animation, everything works smoothly The problem occurs only on a real device. I've tested on iOS 17 and 18 Example code struct ContentView: View { @State var open = false let colors: [Color] = [.cyan, .red, .green, .gray, .blue, .orange, .pink, .purple] @State var i: Int = 0 @State var text: String = chunks[0] @State var pause = false var body: some View { ZStack { TimelineView(.animation(minimumInterval: 1.2, paused: pause)) { context in let color = colors[Int(context.date.timeIntervalSinceReferenceDate) % colors.count] ZStack { color .animation(.easeInOut(duration: 1.2)) Rectangle().fill(Material.regular).edgesIgnoringSafeArea(.all) } } VStack { Spacer() Text(text) .font(.system(size: 32)) .multilineTextAlignment(.center) .padding() .animation(.linear(duration: 0.1), value: text) Spacer() Button("Add text") { if i < (chunks.count - 1) { i += 1 } else { i = 0 text = "" } text.append(" " + chunks[i]) } Button("Toggle background animation") { pause.toggle() } } } } } let lyrics = "I'm born to run down rocky cliffs Give me grace, bury my sins Shattered glass and black holes Can't hold me back from where I need to go" let chunks = lyrics.components(separatedBy: " ")
0
1
111
4w
Equal width buttons in VStack
I can't wrap my head around how to make two buttons the same width, without resorting to ugly hacks like GeometryReader. What is otherwise easy to implement using UIStackView or AutoLayout, becomes a nightmare in SwiftUI. I tried the following, plus some other variations, but nothing works. What is the "official way" to make two vertically aligned buttons of the same width? 1) VStack(alignment: .leading) { Button("Short", action: {}) .frame(maxWidth: .infinity) Button("Long title", action: {}) .frame(maxWidth: .infinity) } .frame(maxWidth: .infinity) 2) VStack(alignment: .leading) { Button(action: {}) { Text("Short") .frame(maxWidth: .infinity) } Button(action: {}) { Text("Long title") .frame(maxWidth: .infinity) } } .frame(maxWidth: .infinity) 3) VStack(alignment: .leading) { Button(action: {}) { Text("Short") }.frame(maxWidth: .infinity) Button(action: {}) { Text("Long title") }.frame(maxWidth: .infinity) } .frame(maxWidth: .infinity)
3
0
209
4w
AreaMark Always alignsMarkStylesWithPlotArea for linear gradients
I'm trying to make a Swift Chart where 24 AreaMarks an hour apart on X axis over a day display a vertical gradient. The gradient is vertical and is essentially [Color.opacity(0.1),Colour,Color.opacity(0.1] The idea here is where the upper and lower points of each AreaMark are the same or close to each other in the Y axis, the chart essentially displays a line, where they are far apart you get a nice fading vertical gradient. However, it seems that the .alignsMarkStylesWithPlotArea modifier is always set for AreaMarks even if manually applying it false. Investigating further, I've learnt that with AreaMarks in a series, Swift Charts seems to only listen to the first foreground style set in. I've created some sample code to demonstrate this. struct DemoChartView: View { var body: some View { Chart { AreaMark(x: .value("Time", Date().addingTimeInterval(0)), yStart: .value("1", 40), yEnd: .value("2", 60)) .foregroundStyle(LinearGradient(colors: [.pink, .teal], startPoint: .top, endPoint: .bottom)) .alignsMarkStylesWithPlotArea(false) AreaMark(x: .value("Time", Date().addingTimeInterval(3600)), yStart: .value("1", 44), yEnd: .value("2", 58)) .foregroundStyle(LinearGradient(colors: [.orange, .yellow], startPoint: .top, endPoint: .bottom)) .alignsMarkStylesWithPlotArea(false) AreaMark(x: .value("Time", Date().addingTimeInterval(03600*2)), yStart: .value("1", 50), yEnd: .value("2", 90)) .foregroundStyle(LinearGradient(colors: [.green, .blue], startPoint: .top, endPoint: .bottom)) .alignsMarkStylesWithPlotArea(false) } } } Which produces this: So here, all the different .foregroundStyle LinearGradients are being ignored AND the .alignsMarkStylesWithPlotArea(false) is also ignored - the amount of pink on the first mark is different to the second and third 🤷‍♂️ Has anyone encountered this. Are AreaMarks the correct choice or are they just not setup to create this type of data display. Thanks
2
0
193
4w
How can I get a tab-bar styled ornament on the trailing edge of a view controller?
I've got a UIKit app with a collapsible trailing-edge child view controller, implemented sort of like UISplitViewController but it's got a bunch of custom behavior - moving to the bottom edge in portrait orientation, etc. It exposes a couple of different app functions via a UITabBar on the bottom edge on iOS. When I run the app on visionOS, that tab bar transforms to a leading-edge ornament. This would be great, but that means it tries to overlap the trailing-edge content of its parent view controller, which isn't ideal. Is there a way to get the tab bar to lay out on the trailling edge of the child view controller? Or can I create a custom ornament that has the same auto-expand behavior as the tab bar, where it shows a vertical column of icons that expands to show titles when you're gazing at it?
1
0
191
4w