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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

SwiftUI Core Data Relationship Not Updating View
I've run into a problem with the following setup: I have a Core Data database with parent objects with a relationship to many child objects. I have a main view using SwiftUI FetchedResults that displays the parent objects in a list and properties about the child objects. I have a second view that lets you change properties of the child objects. The parent object has the property: name (string). The child object has: name (string) and star (bool). On the main view I display a list of parent objects and how many child objects are starred. On the second view I update if a child object is starred. Upon updating the property on the second view and saving, the first view does not update until you relaunch the app. Here is the main view: struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext @FetchRequest(sortDescriptors: [SortDescriptor(\.name)]) private var parents: FetchedResults<Parent> @State private var editingParent: Parent? var body: some View { List { ForEach(parents) { parent in VStack(alignment: .leading) { Text(parent.name ?? "No Name") Text("\(parent.children!.count) children") Text("\(getNumberOfStar(parent: parent)) Stared") } .onTapGesture { editingParent = parent } } } .sheet(item: $editingParent) { parent in ChildrenView(parent: parent) } Button { PersistenceController.shared.saveParent(name: "New Parent") } label: { Text("Add Parent") }.padding() Button { parents.forEach { parent in PersistenceController.shared.delete(parent: parent) } } label: { Text("Delete All") }.padding() } //this function does not get called when the database changes func getNumberOfStar(parent: Parent) -> Int { let children = parent.children!.allObjects as! [Child] let starred = children.filter({$0.star == true}) return starred.count } } This is the child view: @FetchRequest var children: FetchedResults<Child> var parent: Parent init(parent: Parent) { self.parent = parent _children = FetchRequest<Child>(sortDescriptors: [], predicate: NSPredicate(format: "parent = %@", parent)) } var body: some View { List { ForEach(children) { child in HStack { Text(child.name ?? "No Name") Text(child.star ? "⭐️" : "") Spacer() Button { PersistenceController.shared.updateStar(child: child) } label: { Text("Toggle Star") } } } } Button { PersistenceController.shared.saveChild(name: "New Child", parent: parent) } label: { Text("Add Child") } } } This is the Persistence Controller: static let shared = PersistenceController() let container: NSPersistentContainer init(inMemory: Bool = false) { container = NSPersistentContainer(name: "Model") if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") } container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. /* Typical reasons for an error here include: * The parent directory does not exist, cannot be created, or disallows writing. * The persistent store is not accessible, due to permissions or data protection when the device is locked. * The device is out of space. * The store could not be migrated to the current model version. Check the error message to determine what the actual problem was. */ fatalError("Unresolved error \(error), \(error.userInfo)") } }) container.viewContext.automaticallyMergesChangesFromParent = true } func save() { let viewContext = container.viewContext do { try viewContext.save() } catch { /** Real-world apps should consider better handling the error in a way that fits their UI. */ let nsError = error as NSError fatalError("Failed to save Core Data changes: \(nsError), \(nsError.userInfo)") } } func saveParent(name: String) { let newParent = Parent(context: container.viewContext) newParent.name = name save() } func saveChild(name: String, parent: Parent) { let newChild = Child(context: container.viewContext) newChild.name = name newChild.parent = parent newChild.star = false save() } func updateStar(child: Child) { child.star.toggle() save() } func delete(parent: Parent) { let viewContext = container.viewContext viewContext.delete(parent) save() } } Finally here is the App struct: struct Core_Data_Child_Save_ExampleApp: App { let persistenceController = PersistenceController.shared var body: some Scene { WindowGroup { ContentView() .environment(\.managedObjectContext, persistenceController.container.viewContext) } } }
4
0
277
2w
TabView with ScrollView: scroll position ID not updating when tapping Tab item
When working with SwiftUI TabView and ScrollView at root level with scrollPosition(id:anchor:), after tapping on Tab item the ScrollView scrolls to the top, but the scroll position ID does not get updated. struct ContentView: View { @State var positionID: Int? var body: some View { TabView { Tab("Test", systemImage: "house") { ScrollView(.vertical) { LazyVStack(pinnedViews: [.sectionHeaders]) { ForEach(0 ... 100, id: \.self) { index in Text("\(index)") } } .scrollTargetLayout() } .scrollPosition(id: $positionID, anchor: .top) .onChange(of: positionID) { _, newValue in print(newValue) } } } } } FB15964820
0
0
139
2w
Widget with dynamic property and clearing the option.
I have a widget with a dynamic property. I'm able to provide the options to the widget edit ui and the user can make their selection .. which filters what data gets shown in the widget. My use case is when the user goes back to the main app and deletes the option that is currently selected. Currently, the widget keeps that selection. How can I get the widget to clear that selection and show the defaultResult() from the EntityQuery?
0
0
119
2w
Canvas view crashing with Core Graphics-based drawing
One of my SwiftUI applications using a Canvas view started to crash with Xcode 16. It was working flawlessly with Xcode 15. I was able to come up with a minimal SwiftUI app that shows the issue: @main struct CanvasTest: App { var body: some Scene { WindowGroup { VStack { Canvas { context, size in context.withCGContext { cgContext in let z = Int(size.width / 3.0) for i in 0..<18000 { // crashes from 17413 on cgContext.beginPath() cgContext.move(to: CGPoint(x: (i % z) * 3, y: (i / z) * 2)) cgContext.addLine(to: CGPoint(x: (i % z) * 3 + 2, y: (i / z) * 2)) cgContext.strokePath() } } } } } } } The canvas displays 18000 lines and the context.withCGContext invocation also completes successfully. Yet, the application crashes immediately after like this (details below): Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001800eabb4 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [2162] I was wondering if anyone else noticed that change and found a way to fix it? Alternatively, I am looking for workarounds. I have to be able to display large drawings created via core context-based graphics. Is this worth reporting to Apple? Thanks already now for any help and advice. Hardware Model: Mac15,9 Process: CanvasTest [2162] Path: /Users/USER/Library/Developer/CoreSimulator/Devices/0C372C7C-3D00-48AA-8124-799CB9A35C1E/data/Containers/Bundle/Application/EBAEC7A2-C93D-48B7-9754-4F3F54A33084/CanvasTest.app/CanvasTest Identifier: com.objecthub.CanvasTest Version: 1.0 (1) Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd_sim [98324] Coalition: com.apple.CoreSimulator.SimDevice.0C372C7C-3D00-48AA-8124-799CB9A35C1E [58431] Responsible Process: SimulatorTrampoline [3499] Date/Time: 2024-12-01 14:33:07.7617 +0100 Launch Time: 2024-12-01 14:33:07.4151 +0100 OS Version: macOS 15.1.1 (24B91) Release Type: User Report Version: 104 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001800eabb4 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [2162] Triggered by Thread: 0 Application Specific Information: Abort Cause 268435470 Thread 0 Crashed:: Dispatch queue: com.Metal.CommandQueueDispatch 0 libxpc.dylib 0x1800eabb4 _xpc_connection_release_message.cold.1 + 60 1 libxpc.dylib 0x1800c9910 _xpc_connection_release_message + 240 2 libxpc.dylib 0x1800c80b4 _xpc_connection_enqueue + 264 3 libxpc.dylib 0x1800c8b9c xpc_connection_send_message + 128 4 MTLSimDriver 0x2275c6e7c -[MTLSimCommandQueue submitCommandBuffers:count:] + 368 5 Metal 0x19eabdfd4 -[_MTLCommandQueue _submitAvailableCommandBuffers] + 480 6 Metal 0x19eabe4ac __40-[_MTLCommandQueue submitCommandBuffer:]_block_invoke + 24 7 libdispatch.dylib 0x180178de0 _dispatch_client_callout + 16 8 libdispatch.dylib 0x180188ac8 _dispatch_lane_barrier_sync_invoke_and_complete + 92 9 Metal 0x19eabe46c -[_MTLCommandQueue submitCommandBuffer:] + 112 10 MTLSimDriver 0x2275c5fc8 -[MTLSimCommandBuffer commitAndWaitUntilSubmitted] + 40 11 RenderBox 0x1c6e9015c RB::RenderFrame::~RenderFrame() + 240 12 RenderBox 0x1c6e6e9dc __38-[RBLayer displayWithBounds:callback:]_block_invoke.27 + 500 13 libdispatch.dylib 0x180178de0 _dispatch_client_callout + 16 14 libdispatch.dylib 0x180188ac8 _dispatch_lane_barrier_sync_invoke_and_complete + 92 15 RenderBox 0x1c6e6de38 -[RBLayer displayWithBounds:callback:] + 2480 16 RenderBox 0x1c6e6d46c -[RBLayer display] + 172 17 QuartzCore 0x18b0c7e74 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 392 18 QuartzCore 0x18affca50 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 464 19 QuartzCore 0x18b02b260 CA::Transaction::commit() + 652 20 UIKitCore 0x185af0f70 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 32 21 CoreFoundation 0x18041b58c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20 22 CoreFoundation 0x18041acc4 __CFRunLoopDoBlocks + 352 23 CoreFoundation 0x1804153cc __CFRunLoopRun + 812 24 CoreFoundation 0x180414c24 CFRunLoopRunSpecific + 552 25 GraphicsServices 0x19020ab10 GSEventRunModal + 160 26 UIKitCore 0x185ad82fc -[UIApplication _run] + 796 27 UIKitCore 0x185adc4f4 UIApplicationMain + 124 28 SwiftUI 0x1d290b41c closure #1 in KitRendererCommon(_:) + 164 29 SwiftUI 0x1d290b144 runApp<A>(_:) + 84 30 SwiftUI 0x1d266bef4 static App.main() + 148 31 CanvasTest.debug.dylib 0x105061c64 static CanvasTest.$main() + 40 32 CanvasTest.debug.dylib 0x105061d14 __debug_main_executable_dylib_entry_point + 12 (CanvasTest.swift:11) 33 dyld_sim 0x10519d410 start_sim + 20 34 dyld 0x10539a274 start + 2840 Thread 4:: com.apple.uikit.eventfetch-thread 0 libsystem_kernel.dylib 0x1050f5290 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x1051066c4 mach_msg2_internal + 76 2 libsystem_kernel.dylib 0x1050fd3f4 mach_msg_overwrite + 536 3 libsystem_kernel.dylib 0x1050f55cc mach_msg + 20 4 CoreFoundation 0x18041b000 __CFRunLoopServiceMachPort + 156 5 CoreFoundation 0x180415528 __CFRunLoopRun + 1160 6 CoreFoundation 0x180414c24 CFRunLoopRunSpecific + 552 7 Foundation 0x180f319c8 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 208 8 Foundation 0x180f31be8 -[NSRunLoop(NSRunLoop) runUntilDate:] + 60 9 UIKitCore 0x185b858c0 -[UIEventFetcher threadMain] + 404 10 Foundation 0x180f58810 __NSThread__start__ + 720 11 libsystem_pthread.dylib 0x10507f6f8 _pthread_start + 104 12 libsystem_pthread.dylib 0x10507a940 thread_start + 8
0
0
166
3w
iPad app now crashing on Mac. layoutSubtreeIfNeeded ?
My ipAd app is now crashing when being run on a Mac (with designed for iPad emulator). It. has been working a month ago, today was first time I tried in awhile. I get a warning "It's not legal to call -layoutSubtreeIfNeeded on a view which is already being laid out. If you are implementing the view's -layout method, you can call -[super layout] instead. Break on void _NSDetectedLayoutRecursion(void) to debug. This will be logged only once. This may break in the future." shortly after that the App Crashes. Thread 1: EXC_BAD_ACCESS (code=1, address=0x14a0839653d0) The crash happens when my main view (in a Tab view) goes to a DetailView. I stripped out all functionality in my code and it still happens mainView NavigationLink{ ImageDetailView2 () } label: { img } struct ImageDetailView2: View { var body: some View { Text("Hello, World!") } } Any help would be appreciated
3
0
179
3w
Error: Value of type 'SettingsView' has no member 'tabItem'
I'm going through the tutorial and have copied the code given to me verbatim, but I am still getting the error 'Value of type 'SettingsView' has no member 'tabItem'. Not sure what to do. Code is below. import SwiftUI @main struct MyApp: App { var body: some Scene { WindowGroup { TabView { ContentView() .tabItem { Label("Journal", systemImage: "book") } SettingsView() .tabItem { *error is here - Value of type 'SettingsView' has no member 'tabItem' Label("Settings", systemImage: "gear") } } } } }
1
0
160
3w
How to update data in a DataFrame
My project loads a CSV into a DataFrame and displays it in a Table (a MacOS app). So far so good ... but when trying to update a value in a column, I dont see anyway to update this value. The table gets the value for the column like this: func getColumnValue(row :DataFrame.Rows.Element, columnName :String) -&gt; String { if row.base.containsColumn(columnName) { var value = "" if row[columnName] != nil { value = "\(row[columnName]!)" } return value } ... But the documentation and googles dont show any way to update the same column. Any help is appreciated with cookies. Attempt to update: func setColumnValue(row :DataFrame.Rows.Element, columnName :String, value :String) { var column: [String?] = data[columnName] column[row.id] = value ... }
6
0
263
3w
Getting multi-stage text input status in SwiftUI
Hi all, Is there way to check the status of multi-stage text input in the TextField of SwiftUI? I am essentially trying to detect if the user is entering some text with multi-stage text input method right now. (e.g., Japanese, Chinese, etc). TextField("Search", text: $searchText) .onKeyPress(keys: [.upArrow, .downArrow]) { event in if ....some condition here... { // ignore up/down keys when multi-stage input return .ignored } else { // do some special key handling // when multi-stage input is not running return .handled } } Multi-stage text input uses up/down keys to choose words from candidates, so I don't want to handle the keys when it is happening.
0
0
126
3w
Swift Charts legend overflowing outside frame
I'm building an app that lets users create charts with custom values and while testing, I came up with this bug that happens when the view width forces the legend to have more than 1 line. Due to Swift trying to align the different labels vertically, it's forcing the first line to overflow. Here's the code to generate this: import SwiftUI import Charts struct DonutView: View { var countries:[(country:String, count:Int)] = [ (country: "Africa", count: 54), (country: "Asia", count: 48), (country: "Europe", count: 44), (country: "North America", count: 23), (country: "Oceania", count: 14), (country: "South America", count: 12), ] var body: some View { Chart { ForEach(0..<countries.count, id:\.self) { idx in SectorMark( angle: .value(countries[idx].country, countries[idx].count), innerRadius: .ratio(0.5) ) .foregroundStyle(by: .value("label", countries[idx].country)) } } .frame(width: 310, height: 270) .border(.blue, width: 1) } } Has anyone seen this? Is there a solution? I know about building custom legends, but SwiftUI has no wrapping HStack nor VStack, and the app allows users to change the legend position from the bottom to the top or sides. If I were to go this way, I'd have to write a very large chunk of code to bypass what seems to be a bug.
1
0
178
3w
Carousel Flicker
Hi, I've created an carousel using an Tabview component and it is divided in pages, each page has 7 items. Now we wan't to load the carousel page by page, but whenever I updated the list which Tabview uses to render, it flickers because it rerenders previous elements. I've tried to use a scroll view for this but this app is for Vision Pro and I added some 3D transformations (position/rotation) to the cards from the tabview and when I added this in the scrollview they becom unclickable. Do you have any sugestions what can I do? Bellow is a sample of the code, I put [items] just to suggest there is a list. VStack (spacing: 45) { TabView(selection: $navigationModel.carouselSelectedPage) { let orderedArtist = [items] let numberOfPages = Int((Double(orderedArtist.count) / Double(cardsPerPage)).rounded(.up)) if(numberOfPages != 1){ Spacer().tag(-1) } ForEach(0..<numberOfPages, id: \.self) { page in LazyHStack(alignment: .top, spacing: 16){ ForEach(0..<cardsPerPage, id: \.self) { index in if(page * cardsPerPage + index < orderedArtist.count){ let item = orderedArtist[page * cardsPerPage + index] GeometryReader{proxy in
1
0
176
3w
Broken focus on TabView with more than 7 tabs on tvos18
I am using the TabView control in SwiftUI on a tvOS 18 target with the style of sidebarAdaptable. When I have 7 or less tabs things operate correctly. When I add an 8th tab and you navigate to the contents of the tab the menu collapses as expected but you cannot navigate back to restore the menu. This code reproduces the issue: import SwiftUI struct ContentView: View { var body: some View { TabView { Tab("Tab1", systemImage: "person.circle") { Button("Button1") {} } Tab("Tab2", systemImage: "person.circle") { Button("Button2") {} } Tab("Tab3", systemImage: "person.circle") { Button("Button3") {} } Tab("Tab4", systemImage: "person.circle") { Button("Button4") {} } Tab("Tab5", systemImage: "person.circle") { Button("Button5") {} } Tab("Tab6", systemImage: "person.circle") { Button("Button6") {} } Tab("Tab7", systemImage: "person.circle") { Button("Button7") {} } Tab("Tab8", systemImage: "person.circle") { Button("Button8") {} } } .tabViewStyle(.sidebarAdaptable) } } If you eliminate Tab 8 the problem goes away. You can navigate back to the menu by moving to the left. Notably the Destination Video sample also reproduces this issue: https://developer.apple.com/documentation/visionos/destination-video To reproduce: Load the above code or Destination Video sample. Navigate right (click right on remote or swipe right). Menu dismisses and just shows the item you have selected in the upper left corner. Try to navigate left by clicking left on the remote or swiping left. It looks like the collapsed menu gets focus briefly, screen elements flash but the focus remains outside the menu. Has anyone else encountered this issue?
1
2
157
3w
Infinite view loop
If I add items at the root level, this code works, but if I attempt to add a child to any item, it runs an infinite loop where it goes from the AddItemView back to the SubItemView and starts all over. I suspect it has something to do with the Predicate in SubItemView, but the debugger is crap, so I'm just guessing. Minimal code: @Model final class Item { var id: String var name: String var children: [Item] = [] @Relationship(deleteRule: .cascade) var parent: Item? init(name: String, parent: Item?, id: String = UUID().uuidString) { self.name = name self.parent = parent self.id = id } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query( filter: #Predicate<Item> { item in item.parent == nil }, sort: \Item.name ) public var rootItems: [Item] var body: some View { NavigationStack { List { ForEach(rootItems) { item in HStack { NavigationLink ( destination: SubItemView(parent: item)) { Text(item.name) } } } } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { NavigationLink(destination: AddItemView(itemParent: nil)) { Text("Add To Do") } } } } } } struct SubItemView: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) private var modelContext @State var parent: Item @State private var todo: String = "" @State var selectedDate = Date() @State var showPicker: Bool = false @Query var children: [Item] init(parent: Item) { self.parent = parent let parentID = parent.id _children = Query(filter: #Predicate<Item> { $0.parent.flatMap(\.id) == parentID && $0.parent.flatMap(\.id) != nil }, sort: \Item.name ) } var body: some View { Form { LabeledContent { TextField("Name", text: $parent.name) } label: { Text("Name:") } } Text("Parent: \(parent.name)\n") NavigationStack { Text("Child count: \(children.count)") List(children) { child in HStack { if(child.children.isEmpty) { Text(child.name) NavigationLink ( destination: SubItemView(parent: child)) { Text("").foregroundColor(.white).background(Color.blue) } .opacity(0) .background( Text("") ) } else { Text(child.name) NavigationLink(destination: SubItemView(parent: child)) { Text("") } } } } } .navigationTitle("Sub Items") .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { NavigationLink(destination: AddItemView(itemParent: parent)) { Text("Add To Do") } } ToolbarItem { Button("Save") { try? modelContext.save() dismiss() } } } } } struct AddItemView: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) private var context @State var itemParent: Item? @State private var name = "" @State private var showWarning: Bool = false @State var child = Item(name: "", parent: nil) var body: some View { NavigationStack { Form { LabeledContent { TextField("Item", text: $name) } label: { Text("Todo:") } } .navigationTitle("Add New Item") .toolbar { Button("Save") { let tmp = Item(name: name, parent: itemParent) if(itemParent != nil) { itemParent!.children.append(tmp) } context.insert(tmp) try? context.save() dismiss() } } } } }
4
0
226
3w
SwiftUI View incorrectly disabled based on position?
My app has a sort of "HUD" that sits at the top of the screen. It contains some general information about gameplay, and a couple of interactive elements: a scrolling list of text and a button. It's imbedded into the main view like this: struct WindowedInGameView: View { @Environment(GameModel.self) private var gameModel var body: some View { ZStack(alignment: .top) { VStack { HUDTopView() switch(gameModel.game?.location.player_location) { case .plaza: PlazaView() case .city_hall: CityHallView() ///... Lots of additional views... default: Text("Player is in unknown location.") } // --> Position 2 } if gameModel.showConversationView { ... an overlay for NPC conversations... } if (gameModel.showNotificationView) { .. a notification overlay... } } } } If HUDTopView() is at the indicated place at the top of the VStack, none of its interactive elements work: you can't press buttons, you can't scroll the text. Everything looks present and interactive, it just doesn't seem to receive any input. If I move HUDTopView() to the bottom of the VStack (where the comment indicates "Position 2") it works just fine, except it's not where I want it to be located. So far as I can tell, its position alone is disabling it somehow. In either case, any interactive elements in the views from the switch are acting fine, regardless of their position relative to the HUD view. This fails in the same way on iOS, iPadOS, and macOS. (The visionOS implementation doesn't use this main view, so I haven't tried it there). What it isn't: the overlays at the bottom. Commenting them out doesn't change behaviour. the ZStack - I can replace it with an HStack, and it still fails. Anything about the container of this view -- it fails in preview Anything about the HUDTopView() -- a simple button placed there becomes noninteractive, too. I'm at a complete loss for what could possibly be causing this.
1
0
180
3w
How to do content transition when one image is a system symbol and the other is in assets catalouge?
I have a save button: Button(action: { saveTapped() }) { Label("Save", systemImage: wasSaved ? "checkmark" : "square.and.arrow.down") } .contentTransition(.symbolEffect(.replace)) .disabled(wasSaved) Now, I created a new custom icon and added it into the assets catalogue: "custom.square.and.arrow.down.badge.checkmark" for when the wasSaved state is true. The issue I am facing is that to use it I need to use the method of Label with image:, while to use the non custom symbol, I need to use systemImage:. So how is it possible to transition between the two?
1
0
181
3w
SwiftUI Popover Crash During Resizing in Stage Manager
SwiftUI Popover Crash on iPad During Resizing in Stage Manager with Exception. *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Trying to layout popover in the delegate callback popoverPresentationController:willRepositionPopoverToRect:inView: will lead to recursion. Do not force the popover's container view or an ancestor to layout in this callback.' (Occurred from iPadOS 18.1) struct ContentView: View { @State var showPopover: Bool = false var body: some View { VStack { Text("Hello, world!") Button(action: { showPopover = true }, label: { Text("Open Popover") }) } .padding() .popover(isPresented: $showPopover, attachmentAnchor: .point(.trailing), content: { VStack { Text("Popover Content") } }) } }
7
5
339
3w
Issue with NavigationStack, TabView and List
Hi, I'm experiencing a layout issue in SwiftUI when using TabView, NavigationStack, and a List in a specific navigation flow. Here's how to reproduce it: Tap on Tab 3. Tap "Tap Me to go to the subview" to navigate to the detail view. In the detail view, tap Back to return to Tab 3. Tap "Tap Me to go to the subview" again. Problem: When returning to the detail view, the content (especially the List) appears incorrectly positioned within the safe area, as if it's overlapping or misaligned with the navigation bar. This happens only when navigating back and forth after dismissing a sheet presented from a different tab. This animated gif shows the workflow to visualize the problem: Expected Behavior: The content should consistently respect the safe area and be positioned correctly under the navigation bar. Thanks in advance for your help! Here is the complete code to reproduce the issue: import SwiftUI @Observable class MenuSelector { var initialIndex: Int var customTabIndex: Int var isCustomTabSelected: Bool = false private var previousIndex: Int init(customTabIndex: Int, initialIndex: Int = 0) { self.initialIndex = initialIndex self.customTabIndex = customTabIndex self.itemSelected = initialIndex self.previousIndex = initialIndex } var itemSelected: Int { didSet { if itemSelected == customTabIndex { previousIndex = oldValue itemSelected = oldValue isCustomTabSelected = true } } } } struct NavigationStackSpikeView: View { @State private var tabSelector = MenuSelector(customTabIndex: 1) var body: some View { TabView(selection: $tabSelector.itemSelected) { Text("Tab 1") .tabItem { Text("Tab 1") } .tag(0) Text("I want to present a sheet for this tab") .tabItem { Text("Action") } .tag(1) Tab3View() .tabItem { Text("Tab 3") } .tag(2) } .sheet(isPresented: $tabSelector.isCustomTabSelected) { SheetView() } } } struct Tab3View: View { @State private var navigationPath = NavigationPath() var body: some View { NavigationStack(path: $navigationPath) { VStack { NavigationLink(value: Destination.subview) { Text("Tap Me to go to the subview") } } .navigationDestination(for: Destination.self) { destination in switch destination { case .subview: DetailView() } } } } enum Destination: Hashable { case subview } } struct DetailView: View { var body: some View { VStack { List { Text("A detail") } .listStyle(.plain) } .navigationTitle("Details") .navigationBarTitleDisplayMode(.inline) } } struct SheetView: View { @Environment(\.dismiss) var dismiss var body: some View { VStack { Text("I'm a sheet") Button("Dismiss") { dismiss() } } } } #Preview { NavigationStackSpikeView() }
0
0
151
3w
How can I make an "inverted" list (bottom to top) with SwiftUI?
I'm trying to figure out how to make an inverted list in my watchOS app for a message view, so that messages appear from the bottom first, and go up. Everything I've tried so far has some sort of major drawback, and I'm wondering if there's some proper way to do it. My current implementation is flipping every message item upside-down, then flipping the whole list upside-down. This works in making the list go from bottom to top, but the digital crown scroll direction is also inverted. Simply inverting the array of messages doesn't work either, as the user has to scroll to the bottom of the list manually every time. Any tips/suggestions would be greatly appreciated.
0
0
182
3w
Linked list?
The code below works, in that it successfully creates an item and attached it to the parent item, but the parent view doesn't show the new child until you navigate away from the parent and then back to it. Parent: Child1 Child2 // Add Child 3 and this does not refresh when returning through the dismiss() call, but if I navigate to the grand Parent, and then back to the Parent, Child 3 is there. Any ideas? NavigationStack { Form { LabeledContent { TextField("Item", text: $name) } label: { Text("Item:") } } .navigationTitle("Add New Item") .toolbar { Button("Save") { var tmp = Item(timestamp: Date(), name: name, parent: itemParent) if(itemParent != nil) { itemParent!.children.append(tmp) } context.insert(tmp) try? context.save() dismiss() } } }
2
0
276
3w