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

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
230
Oct ’24
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
426
Oct ’24
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
314
Oct ’24
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
270
Oct ’24
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
195
Oct ’24
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
221
Oct ’24
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
255
Oct ’24
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
146
Oct ’24
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
350
Oct ’24
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
313
Oct ’24
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
279
Oct ’24
SwiftUI warning for "Publishing changes from within view updates" on macOS
I have a simple example of a List with multiple selection. When I run it on macOS, and select an item from the list, it works fine but I get a warning in the console: Publishing changes from within view updates is not allowed, this will cause undefined behavior Interestingly, it doesn't produce a purple 'issue' in the Issues navigator, but as I change selection, I keep getting this warning. Also, the warning doesn't show when running the same code on iOS. Here is code to reproduce it: struct TestListSelection: View { let testArray = [TestItem(itemValue: 1), TestItem(itemValue: 2), TestItem(itemValue: 3), TestItem(itemValue: 4)] @ObservedObject var listOptions: TestListViewModel var body: some View { List (selection: $listOptions.multipleSelection) { Section("Header") { ForEach (testArray, id: \.self) { item in Button { print("row tapped - \(item.itemValue)") } label: { VStack { HStack { Text(item.itemString) } } } .buttonStyle(.plain) } } } .listStyle(.plain) } } public struct TestItem: Identifiable, Hashable { public let id = UUID() let itemValue: Int var itemString: String { get { return "test \(itemValue)" } } } @MainActor public class TestListViewModel: NSObject, ObservableObject { @Published public var multipleSelection = Set<TestItem>() } I annotated the view model with @MainActor as suggested in other threads, but it doesn't silence the warning. If I move the multipleSelection into the view itself, and make it a @State variable (bypassing the viewModel completely), it works and doesn't produce a warning. But I need it work so I can pass in selection from the UIKit part of the app as well. I also can't migrate to @Observable because my main project has to support iOS15 and above. Any clue why this is happening on macOS specifically, and what I can do to avoid it?
0
0
247
Oct ’24
List: Why does the destination value seem to be 0-based in one direction and 1-based in another with .onMove?
I ran into this with a more complex project, but was able to recreate with a very simple example below. I have a List with five items in it. I use a ForEach on the items with .onMove. The onMove function has a destination value. If my list is: A, B, C, D, E, and I drag B so it is below C, I would expect to get A, C, B, D, E. Further, I would expect that destination would be 2, since I am moving B to the 3rd index, assuming that A is at index 0. Weirdly, destination is always 3. Conversely, if I do the opposite, and drag C so it is above B, and I get A, C, B, D, E, destination is now 1! This makes sense, since it's the second position. So why is it that moving down the list results in what appears to be 1-based indexing, but moving it up the list seems to be 0-based indexing? How am I supposed to reliably get the correct destination value? @State var items = ["A", "B", "C", "D", "E"] var body: some View { NavigationStack { List { ForEach(items, id: \.self) { item in Text(item) } .onMove(perform: moveItem) } .toolbar { ToolbarItem { EditButton() } } } } private func moveItem(from source: IndexSet, to destination: Int) { print("destination is \(destination)") } } Output from above. If I drag B below C: destination is 3 If I drag C above B: destination is 1
0
0
180
Oct ’24
How do I make a toolbar-style window ornament from UIKit?
I've got a UIKit app and I want to add some buttons in a top-edge window ornament. I'm looking at the WWDC23 talk Meet UIKit for Spatial Computing, and it does exactly what I think I want to do: extension EditorViewController { func showEditingControlsOrnament() { let ornament = UIHostingOrnament(sceneAlignment: .bottom, contentAlignment: .center) { EditingControlsView(model: controlsViewModel) .glassBackgroundEffect() } self.ornaments = [ornament] editorView.style = .edgeToEdge } } But the thing I really want to know is what is in EditingControlsView. Is it a toolbar? How do you make a toolbar in SwiftUI without something to attach the .toolbar modifier to?
1
0
239
Oct ’24
iOS 18 update causes toolbar display regression
Hi there, I'm having an app developed in the last weeks, and recently I'm testing it on iOS 18. This following piece of UI code has diff between iOS 18 and iOS version lower than 18. I have a NavigationStack in my homeView, and the display difference is for its toolbar in one destination. I've tried both approaches in code, with header variable or ToolbarItemGroup used directly in the toolbar modifier, both would result in there being a spacer between the body VStack and toolbar, which is unexpected. Here's the code and a demo screenshot. var body: some View { // header VStack(alignment: .leading) { notificationView( iconKey: "ErrorCircle", contentKey: "receivedFile.notification.noNetwork.content" ) fileListView } .toolbar { // header ToolbarItemGroup(placement: .principal) { Button { dismiss() } label: { Image(systemName: "chevron.backward") } .background(Color.yellow) Spacer() Text(LocalizedStringKey("title")) .font( .system(size: 17) .weight(.semibold) ) .background(Color.yellow) Spacer() Button { print("click") } label: { Text("Click") } .background(Color.yellow) } } .navigationBarBackButtonHidden() .onAppear { refreshAllFiles() } } @ToolbarContentBuilder private var header: some ToolbarContent { ToolbarItem(placement: .topBarLeading) { Button { dismiss() } label: { Image(systemName: "chevron.backward") } .background(Color.yellow) } ToolbarItem(placement: .principal) { Text(LocalizedStringKey("receivedFileList.title")) .font( .system(size: 17) .weight(.semibold) ) .background(Color.yellow) } ToolbarItem(placement: .topBarTrailing) { Button { print("click for jumping") } label: { Text("Click for jumping") } .background(Color.yellow) } } Hope I can get some help from the forum on the usage. If not fixable, may I know if this is a known issue that would be fixed in the next upgrades.
3
0
470
Oct ’24