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)
}
}
}
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
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
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?
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
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
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")
}
}
}
}
}
How can I put navigation into an existing program?
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) -> 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
...
}
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.
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.
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
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?
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()
}
}
}
}
}
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.
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?
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")
}
})
}
}
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()
}
what API do you call in IOS to ring an 0800 number (free calling)
I want to put it at the bottom of every screen.
Would be good if it was smart and worked different on MacOS and iPadOS
Love to meet if you are in New Zealand.
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.
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()
}
}
}