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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

DocumentGroup opens an empty document on Mac Catalyst when the "Optimize for Mac" is checked
I am using a Mac Catalyst with SwiftUI for our document-based app with DocumentGroup. The issue is that when we create a new document or open an existing one, the opened view is completely blank. It is only blank/empty when the "Optimzie for Mac" is checked. If it is "Scaled t oMatch iPad", then it works well. Xcode 16.1 macOS 15.1 struct DocumentGroupTestApp: App { var body: some Scene { DocumentGroup(newDocument: WritingAppDocument()) { file in TestView() // it is empty when it gets opened. It does not work if the option "Optimize for Mac" is checked. If it is scale iPad, then it works. } } } struct TestView: View { var body: some View { Text("Hello, World!") } }
2
0
143
2w
fileImporter doesn't do anything on another user's device
Hello, I'm seeing a strange error on another user's device where the SwiftUI file importer doesn't do anything at all. When selecting multiple files and hitting "open", the importer just freezes. Here's a video showing the problem: https://streamable.com/u5grgy I'm unable to replicate on my own device, so I'm not sure what could be going on. I have startAccessingSecurityScopedResource and stopAccessingSecurityResource everywhere I access a file from fileImporter as well.
2
0
101
2w
SwifttData Record Update
Hi When connecting a SwiftData module property to a SwiftUI view such as a text field and the field changes by user the property get updated in the SwiftData database, now suppose I want to run a validation code or delay updates to Database till use click a submit button how to do that ? delay those auto updates if we can name it ? Kind Regards Code Example import SwiftUI import SwiftData struct GListSel2: View { @Bindable var patient: Patient var body: some View { HStack { TextField("Gender", text: $patient.gender) } } }
1
0
117
2w
List Cell - Modifying associated object causes reload of whole list
I've got a List containing Colour objects. Each colour may have an associated Project Colour object. What I'm trying to do is set it up so that you can tap a cell and it will add/remove a project colour. The adding/removing is working, but each time I do so, it appears the whole view is reloaded, the scroll position is reset and any predicate is removed. This code I have so far List { ForEach(colourList) { section in let header : String = section.id Section(header: Text(header)) { ForEach(section) { colour in HStack { if checkIfProjectColour(colour: colour) { Image(systemName: "checkmark") } VStack(alignment: .leading){ HStack { if let name = colour.name { Text(name) } } } Spacer() } .contentShape(Rectangle()) .onTapGesture { if checkIfProjectColour(colour: colour) { removeProjectColour(colour: colour) } else { addProjectColour(colour: colour) } } } } } .onAppear() { filters = appSetting.filters colourList.nsPredicate = getFilterPredicate() print("predicate: on appear - \(String(describing: getFilterPredicate()))") } .refreshable { viewContext.refreshAllObjects() } } .searchable(text: $searchText) .onSubmit(of: .search) { colourList.nsPredicate = getFilterPredicate() } .onChange(of: searchText) { colourList.nsPredicate = getFilterPredicate() } The checkIfProjectColour function func checkIfProjectColour(colour : Colour) -> Bool { if let proCols = project.projectColours { for proCol in proCols { let proCol = proCol as! ProjectColour if let col = proCol.colour { if col == colour { return true } } } } return false } and the add/remove functions func addProjectColour(colour : Colour) { let projectColour = ProjectColour(context: viewContext) projectColour.project = project projectColour.colour = colour colour.addToProjectColours(projectColour) project.addToProjectColours(projectColour) do { try viewContext.save() } catch { let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } } func removeProjectColour(colour: Colour) { if let proCols = project.projectColours { for proCol in proCols { let proCol = proCol as! ProjectColour if let col = proCol.colour { if col == colour { viewContext.delete(proCol) do { try viewContext.save() } catch { let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } } } } } }
2
0
118
2w
I am unable to programmatically hide status Bar
PLATFORM AND VERSION iOS Development environment: Xcode 16, macOS 15.0.1 Run-time configuration: iOS 18.1 DESCRIPTION OF THE PROBLEM I am experiencing inconsistent behaviour in SwiftUI when attempting to hide the status bar programmatically. Specifically, I want the status bar to be hidden only during the AreaQuizView, but the behaviour is not persistent across different views. On some views, the status bar hides correctly, while on others, it does not. I am using .statusBarHidden() to achieve this. STEPS TO REPRODUCE In AreasView, apply .statusBarHidden() to the outermost VStack. The status bar hides as expected. In AreaQuizView, apply the same .statusBarHidden() to the outermost stack. However, in this view, the status bar remains visible. In the Build Targets, if I set Status bar is initially hidden to YES in the info.plist, I lose control over the status bar entirely. EXPECTED BEHAVIOUR I would expect that .statusBarHidden() would behave consistently across all views, allowing me to programmatically hide the status bar only during AreaQuizView and leave it visible for other views. ADVICE REQUESTED Could you please advise on how to achieve the desired behaviour, where the status bar is only hidden during AreaQuizView? I would also appreciate any guidance on ensuring consistent behaviour across different views. Please advise.
3
0
193
2w
Center Map in SwiftUI to specific latitude and longitude.
I have a Map in SwiftUI using MapKit and the map has several annotations and MapCircles added to it. I need to have the ability to center the map on a specific latitude and longitude. The issue is that the map instead is centering so that all annotations and MapCircles etc. are visible. How can I have it disregard items added to the map and center the map at a specific latitude and longitude and ideally, control the zoom level of the map also?
1
0
150
2w
MacOS SwiftUI: Is it impossible to clear a Table selection?
I figured it would be as simple as changing the selection variable back to nil, but that seemingly has no effect. The Table row stays selected, and if I press on it again, it won't trigger my .navigationDestination(). How can I resolve this? I found another post asking the same thing, with no resolution. The only way I can clear it is by clicking with my mouse somewhere else. @State private var selectedID: UUID? = nil Table(tableData, selection: $selectedID, sortOrder: $sortOrder)... .navigationDestination(item: $selectedID, destination: { id in if let cycle = cycles.first(where: {$0.id == id}) { CycleDetailView(cycle: cycle) .onDisappear(perform: { selectedID = nil }) } })
2
0
177
2w
Page view in SwiftUI
I have an app for musicians that works with Songs and Setlists. The logical structure is as follows: A Setlist contains Songs. A Song has Sections, which include Lines (chords & lyrics). I want to view my Setlist in a "Page View," similar to a book where I can swipe through pages. In this view, the Song Sections are wrapped into columns to save screen space. I use a ColumnsLayout to calculate and render the columns, and then a SplitToPages modifier to divide these columns into pages. Problem: The TabView sometimes behaves unexpectedly when a song spans multiple pages during rendering. This results in a transition that is either not smooth or stops between songs. Is there a better way to implement this behavior? Any advice would be greatly appreciated. struct TestPageView: View { struct SongWithSections: Identifiable { var id = UUID() var title: String var section: [String] } var songSetlistSample: [SongWithSections] { var songs: [SongWithSections] = [] //songs for i in 0...3 { var sections: [String] = [] for _ in 0...20 { sections.append(randomSection() + "\n\n") } songs.append(SongWithSections(title: "Song \(i)", section: sections)) } return songs } func randomSection() -> String { var randomSection = "" for _ in 0...15 { randomSection.append(String((0..<Int.random(in: 3..<10)).map{ _ in "abcdefghijklmnopqrstuvwxyz".randomElement()! }) + " ") } return randomSection } var body: some View { GeometryReader {geo in TabView { ForEach(songSetlistSample, id:\.id) {song in let columnWidth = geo.size.width / 2 //song ColumnsLayout(columns: 2, columnWidth: columnWidth, height: geo.size.height) { Text(song.title) .font(.largeTitle) ForEach(song.section, id:\.self) {section in Text(section) } } .modifier(SplitToPages(pageWidth: geo.size.width, id: song.id)) } } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) } } } public struct ColumnsLayout: Layout { var columns: Int let columnWidth: CGFloat let height: CGFloat let spacing: CGFloat = 10 public static var layoutProperties: LayoutProperties { var properties = LayoutProperties() properties.stackOrientation = .vertical return properties } struct Column { var elements: [(index: Int, size: CGSize, yOffset: CGFloat)] = [] var xOffset: CGFloat = .zero var height: CGFloat = .zero } public func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> CGSize { let columns = arrangeColumns(proposal: proposal, subviews: subviews, cache: &cache) guard let maxHeight = columns.map({ $0.height}).max() else {return CGSize.zero} let width = Double(columns.count) * self.columnWidth return CGSize(width: width, height: maxHeight) } public func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) { let columns = arrangeColumns(proposal: proposal, subviews: subviews, cache: &cache) for column in columns { for element in column.elements { let x: CGFloat = column.xOffset let y: CGFloat = element.yOffset let point = CGPoint(x: x + bounds.minX, y: y + bounds.minY) let proposal = ProposedViewSize(width: self.columnWidth, height: proposal.height ?? 100) subviews[element.index].place(at: point, anchor: .topLeading, proposal: proposal) } } } private func arrangeColumns(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> [Column] { var currentColumn = Column() var columns = [Column]() var colNumber = 0 var currentY = 0.0 for index in subviews.indices { let proposal = ProposedViewSize(width: self.columnWidth, height: proposal.height ?? 100) let size = subviews[index].sizeThatFits(proposal) let spacing = size.height > 0 ? spacing : 0 if currentY + size.height > height { currentColumn.height = currentY columns.append(currentColumn) colNumber += 1 currentColumn = Column() currentColumn.xOffset = Double(colNumber) * (self.columnWidth) currentY = 0.0 } currentColumn.elements.append((index, size, currentY)) currentY += size.height + spacing } currentColumn.height = currentY columns.append(currentColumn) return columns } } struct SplitToPages: ViewModifier { let pageWidth: CGFloat let id: UUID @State private var pages = 1 func body(content: Content) -> some View { let contentWithGeometry = content .background( GeometryReader { geometryProxy in Color.clear .onChange(of: geometryProxy.size) {newSize in guard newSize.width > 0, pageWidth > 0 else {return} pages = Int(ceil(newSize.width / pageWidth)) } .onAppear { guard geometryProxy.size.width > 0, pageWidth > 0 else {return} pages = Int(ceil(geometryProxy.size.width / pageWidth)) } }) Group { ForEach(0..<pages, id:\.self) {p in ZStack(alignment: .topLeading) { contentWithGeometry .offset(x: -Double(p) * pageWidth, y: 0) .frame(width: pageWidth, alignment: .leading) VStack { Spacer() HStack { Spacer() Text("\(p + 1) of \(pages)") .padding([.leading, .trailing]) } } } .id(id.description + p.description) } } } }
0
0
154
2w
App Crashes on QuartzCore: CA::Layer::layout_if_needed(CA::Transaction*) + 504
I have facing an above crash for many users device running on iOS 17.6.1 mostly on iPad devices. I'm not sure why this happening only in 17.X. In Xcode Organizer unable to see this crash in any devices running on OS 18.x. Our app crashes got spiked due to this. I am unable to fix or reproduce the same. The crash log is not pointing to our app code to find the root cause and fix this issue. Have attached the crash log in this post also the crash log roles have mixed values Background &amp;amp; Foreground. But most of the crash is in background. Is this any crash related to system and that only solved by OS update? I have updated the app using Xcode 16 and 16.1 still facing this crash unable to symbolicate the crash report as well. Any ideas/solution how to solve this or how to proceed further. Have attached the entire crash log below. RoleBackgroundCrash.crash RoleForeGroundCrash.crash
0
0
154
2w
SwiftUI Lists down arrow handling broken
This has been broken for over 5 years now. I see 2 different behaviors in 2 different SwiftUI apps. This makes SwiftUI not ready for prime time apps, but I just have tools right now. The VStack { List } doesn't scroll to the item in a long list. The selection moves to the next item in the list, but can't see it. This is just basic UI functionality of a list. UIListView doesn't have this issue. The NavigationView { List { NavigationLink }} wraps around back to the top of the list when pressing down arrow past the last visible item, but there are plenty more list items to visit.
3
0
189
3w
Screen on Apple watch turn off even when "Always On" is active
Our company has developed a product available, which measures body composition. During the measurement process, lasting 40 seconds, we require the device screen to remain illuminated. We are actively using the "Always On" feature and have set the timer on the watch to 70 minutes to prevent the screen from dimming. However, we are encountering issues where the screen may still turn off during the measurement. Could you please provide guidance on how to keep the screen active with backlighting across all Apple Watch models during measurements?
2
0
196
3w
Issue with Margin During Navigation Transition in iOS 18+
The new .navigationTransition feature introduced in SwiftUI for iOS 18+ offers an impressive animated screen transition. However, during the transition, the parent view shrinks, leaving a white margin (or black in dark mode) around the edges. If the background color of the parent view matches this margin color, it appears seamless. However, as shown in the attached example, when using a custom color or gradient background, the margin becomes visually disruptive. Is there a way to address this? import SwiftUI struct ContentView: View { @Namespace var namespace var body: some View { NavigationStack { Form { NavigationLink { ZStack { Color.yellow.ignoresSafeArea() Text("Detail View") } .navigationTitle("Transition") .navigationTransition(.zoom(sourceID: "hellow", in: namespace)) } label: { Text("Open") .font(.largeTitle) .matchedTransitionSource(id: "hellow", in: namespace) } } .scrollContentBackground(.hidden) .background(Color.mint.ignoresSafeArea()) } } } #Preview { ContentView() } Applying .ignoreSafeArea() to the background view doesn’t seem to resolve the issue, which suggests this margin might not be related to the safe area. Any insights or solutions would be greatly appreciated.
1
0
158
3w
SwiftUI Gestures: Sequenced Long Press and Drag
In creating a sequenced gesture combining a LongPressGesture and a DragGesture, I found that the combined gesture exhibits two problems: The @GestureState does not properly update as the gesture progresses through its phases. Specifically, the updating(_:body:) closure (documented here) is only ever executed during the drag interaction. Long presses and drag-releases do not call the updating(_:body:) closure. Upon completing the long press gesture and activating the drag gesture, the drag gesture remains empty until the finger or cursor has moved. The expected behavior is for the drag gesture to begin even when its translation is of size .zero. This second problem – the nonexistence of a drag gesture once the long press has completed – prevents access to the location of the long-press-then-drag. Access to this location is critical for displaying to the user that the drag interaction has commenced. The below code is based on Apple's example presented here. I've highlighted the failure points in the code with // *. My questions are as follows: What is required to properly update the gesture state? Is it possible to have a viable drag gesture immediately upon fulfilling the long press gesture, even with a translation of .zero? Alternatively to the above question, is there a way to gain access to the location of the long press gesture? import SwiftUI import Charts enum DragState { case inactive case pressing case dragging(translation: CGSize) var isDragging: Bool { switch self { case .inactive, .pressing: return false case .dragging: return true } } } struct ChartGestureOverlay<Value: Comparable & Hashable>: View { @Binding var highlightedValue: Value? let chartProxy: ChartProxy let valueFromChartProxy: (CGFloat, ChartProxy) -> Value? let onDragChange: (DragState) -> Void @GestureState private var dragState = DragState.inactive var body: some View { Rectangle() .fill(Color.clear) .contentShape(Rectangle()) .onTapGesture { location in if let newValue = valueFromChartProxy(location.x, chartProxy) { highlightedValue = newValue } } .gesture(longPressAndDrag) } private var longPressAndDrag: some Gesture { let longPress = LongPressGesture(minimumDuration: 0.2) let drag = DragGesture(minimumDistance: .zero) .onChanged { value in if let newValue = valueFromChartProxy(value.location.x, chartProxy) { highlightedValue = newValue } } return longPress.sequenced(before: drag) .updating($dragState) { value, gestureState, _ in switch value { case .first(true): // * This is never called gestureState = .pressing case .second(true, let drag): // * Drag is often nil // * When drag is nil, we lack access to the location gestureState = .dragging(translation: drag?.translation ?? .zero) default: // * This is never called gestureState = .inactive } onDragChange(gestureState) } } } struct DataPoint: Identifiable { let id = UUID() let category: String let value: Double } struct ContentView: View { let dataPoints = [ DataPoint(category: "A", value: 5), DataPoint(category: "B", value: 3), DataPoint(category: "C", value: 8), DataPoint(category: "D", value: 2), DataPoint(category: "E", value: 7) ] @State private var highlightedCategory: String? = nil @State private var dragState = DragState.inactive var body: some View { VStack { Text("Bar Chart with Gesture Interaction") .font(.headline) .padding() Chart { ForEach(dataPoints) { dataPoint in BarMark( x: .value("Category", dataPoint.category), y: .value("Value", dataPoint.value) ) .foregroundStyle(highlightedCategory == dataPoint.category ? Color.red : Color.gray) .annotation(position: .top) { if highlightedCategory == dataPoint.category { Text("\(dataPoint.value, specifier: "%.1f")") .font(.caption) .foregroundColor(.primary) } } } } .frame(height: 300) .chartOverlay { chartProxy in ChartGestureOverlay<String>( highlightedValue: $highlightedCategory, chartProxy: chartProxy, valueFromChartProxy: { xPosition, chartProxy in if let category: String = chartProxy.value(atX: xPosition) { return category } return nil }, onDragChange: { newDragState in dragState = newDragState } ) } .onChange(of: highlightedCategory, { oldCategory, newCategory in }) } .padding() } } #Preview { ContentView() } Thank you!
3
0
261
3w
Help Loading an External CSV File on iOS in Swift
Hi everyone! I’m fairly new to Swift and currently working on a small iOS app in SwiftUI. The app is able to load a CSV file embedded in the Xcode project (using Bundle.main.path(forResource:)), and everything works well with that. Now, I want to take it a step further by allowing the app to load an external CSV file located in the iPhone’s directories (like “Documents” or “Downloads”). However, I’m struggling to make it work. I tried using a DocumentPicker to select the CSV file, and I believe I’m passing the file URL correctly, but the app keeps reading only the embedded file instead of the one selected by the user. Could anyone offer guidance on how to properly set up loading an external CSV file? I’m still learning, so any suggestions or examples would be really appreciated! Thanks a lot in advance for the help! Here’s the code that isn’t working as expected: import Foundation struct Product: Identifiable { let id = UUID() var codice: String var descrizione: String var prezzo: Double var installazione: Double var trasporto: Double } class ProductViewModel: ObservableObject { @Published var products: [Product] = [] @Published var filteredProducts: [Product] = [] func loadCSV(from url: URL) { products = [] do { let data = try String(contentsOf: url) let lines = data.components(separatedBy: "\n") // Legge e processa ogni riga del CSV (saltando la prima riga se è l'intestazione) for line in lines.dropFirst() { let values = line.components(separatedBy: ";") // Assicurati che ci siano abbastanza colonne e gestisci i valori mancanti if values.count &gt;= 5 { let codice = values[0].trimmingCharacters(in: .whitespaces) let descrizione = values[1].trimmingCharacters(in: .whitespaces) let prezzo = parseEuropeanDouble(values[2]) ?? 0.0 let installazione = parseEuropeanDouble(values[3].isEmpty ? "0,00" : values[3]) ?? 0.0 let trasporto = parseEuropeanDouble(values[4].isEmpty ? "0,00" : values[4]) ?? 0.0 let product = Product( codice: codice, descrizione: descrizione, prezzo: prezzo, installazione: installazione, trasporto: trasporto ) products.append(product) } } filteredProducts = products } catch { print("Errore nel caricamento del CSV: \(error)") } } private func parseEuropeanDouble(_ value: String) -&gt; Double? { let formatter = NumberFormatter() formatter.locale = Locale(identifier: "it_IT") formatter.numberStyle = .decimal return formatter.number(from: value)?.doubleValue } } struct ContentView: View { @StateObject var viewModel = ProductViewModel() @State private var showFilePicker = false var body: some View { VStack { Button("Carica file CSV") { showFilePicker = true } .fileImporter(isPresented: $showFilePicker, allowedContentTypes: [.commaSeparatedText]) { result in switch result { case .success(let url): viewModel.loadCSV(from: url) case .failure(let error): print("Errore nel caricamento del file: \(error.localizedDescription)") } } List(viewModel.filteredProducts) { product in VStack(alignment: .leading) { Text("Codice: \(product.codice)") Text("Descrizione: \(product.descrizione)") Text("Prezzo Lordo: €\(String(format: "%.2f", product.prezzo))") Text("Installazione: €\(String(format: "%.2f", product.installazione))") Text("Trasporto: €\(String(format: "%.2f", product.trasporto))") } } } .padding() } }
1
0
206
3w
FocusState and pickers error
Hello, since the last version of iOS and WatchOS I have a problem with this code. This is the minimal version of the code, it have two pickers inside a view of a WatchOS App. The problem its with the focus, I can't change the focus from the first picker to the second one. As I said before, it was working perfectly in WatchOS 10.0 but in 11 the problems started. struct ParentView: View { @FocusState private var focusedField: String? var body: some View { VStack { ChildView1(focusedField: $focusedField) ChildView2(focusedField: $focusedField) } } } struct ChildView1: View { @FocusState.Binding var focusedField: String? @State private var selectedValue: Int = 0 var body: some View { Picker("First Picker", selection: $selectedValue) { ForEach(0..<5) { index in Text("Option \(index)").tag("child\(index)") } }.pickerStyle(WheelPickerStyle()).focused($focusedField, equals: "first") } } struct ChildView2: View { @FocusState.Binding var focusedField: String? @State private var selectedValue: Int = 0 var body: some View { Picker("Second Picker", selection: $selectedValue) { ForEach(0..<5) { index in Text("Option \(index)").tag("childTwo\(index)") } }.pickerStyle(WheelPickerStyle()).focused($focusedField, equals: "second") } } When you do vertical scrolling on the second picker, the focus should be on it, but it dosnt anything. I try even do manually, setting the focusState to the second one, but it sets itself to nil. I hope that you can help me, thanks!
3
0
255
3w