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

SwiftUI Documentation

Posts under SwiftUI subtopic

Post

Replies

Boosts

Views

Activity

TabView and Swift Charts giving inconsistent behaviour when swiping between pages
Hi there, I have a TabView in page style. Inside that TabView I have a number of views, each view is populated with a model object from an array. The array is iterated to provide the chart data. Here is the code: TabView(selection: $displayedChartIndex) { ForEach((0..<data.count), id: \.self) { index in ZStack { AccuracyLineView(graphData: tabSelectorModel.lineChartModels[index]) .padding(5) } .tag((index)) } } .tabViewStyle(.page) .indexViewStyle(.page(backgroundDisplayMode: .always)) I am seeing odd behaviour, as I swipe left and right, occasionally the chart area shows the chart from another page in the TabView. I know the correct view is being shown as there are text elements. See the screenshot below. The screen on the right is running iOS 17.2 and this works correctly. The screen on the left is running iOS 17.4 and the date at the top is correct which tells me that the data object is correct. However the graph is showing a chart from a different page. When I click on the chart on the left (I have interaction enabled) then it immediately draws the correct chart. If I disable the interaction then I still get the behaviour albeit the chart never corrects itself because there is no interaction! I can reproduce this in the 17.4 simulator and it is happening in my live app on iOS17.4. This has only started happening since iOS 17.4 dropped and works perfectly in iOS 17.2 simulator and I didn't notice it in the live app when I was running 17.3. Is this a bug and/or is there a workaround? For info this is the chart view code, it is not doing anything clever: struct AccuracyLineView: View { @State private var selectedIndex: Int? let graphData: LineChartModel func calcHourMarkers (maxTime: Int) -> [Int] { let secondsInDay = 86400 // 60 * 60 * 24 var marks: [Int] = [] var counter = 0 while counter <= maxTime { if (counter > 0) { marks.append(counter) } counter += secondsInDay } return marks } var selectedGraphMark: GraphMark? { var returnMark: GraphMark? = nil var prevPoint = graphData.points.first for point in graphData.points { if let prevPoint { if let selectedIndex, let lastPoint = graphData.points.last, ((point.interval + prevPoint.interval) / 2 > selectedIndex || point == lastPoint) { if point == graphData.points.last { if selectedIndex > (point.interval + prevPoint.interval) / 2 { returnMark = point } else { returnMark = prevPoint } } else { returnMark = prevPoint break } } } prevPoint = point } return returnMark } var body: some View { let lineColour:Color = Color(AppTheme.globalAccentColour) VStack { HStack { Image(systemName: "clock") Text(graphData.getStartDate() + " - " + graphData.getEndDate()) // 19-29 Sept .font(.caption) .fontWeight(.light) Spacer() } Spacer() Chart { // Lines ForEach(graphData.points) { item in LineMark( x: .value("Interval", item.interval), y: .value("Offset", item.timeOffset), series: .value("A", "A") ) .interpolationMethod(.catmullRom) .foregroundStyle(lineColour) .symbol { Circle() .stroke(Color(Color(UIColor.secondarySystemGroupedBackground)), lineWidth: 4) .fill(AppTheme.globalAccentColour) .frame(width: 10) } } ForEach(graphData.trend) { item in LineMark ( x: .value("Interval", item.interval), y: .value("Offset", item.timeOffset) ) .foregroundStyle(Color(UIColor.systemGray2)) } if let selectedGraphMark { RuleMark(x: .value("Offset", selectedGraphMark.interval)) .foregroundStyle(Color(UIColor.systemGray4)) } } .chartXSelection(value: $selectedIndex) .chartXScale(domain: [0, graphData.getMaxTime()]) } } }
10
0
1.7k
Mar ’24
Why doesn't my app show up in the accessibility list?
Hello guys, In a macOS app developed with SwiftUI and swift, the NSAccessibility key has been added to the Info.plist file to explain why the app requires Accessibility permissions, and also the AXIsProcessTrustedWithOptions function has been called, but the app is not seen in the system's Accessibility list. I thought, it will show up in the system's Accessibility list like following Some of my code import SwiftUI @available(macOS 13.0, *) @main struct LOKIApp: App { @State private var activeWindow: NSWindow? = nil @State private var accessibilityGranted = false var body: some Scene { MenuBarExtra("App Menu Bar Extra", image: "trayicon") { Button("Settings") {} .keyboardShortcut("s") Divider() Button("Quit") { NSApplication.shared.terminate(nil) } .keyboardShortcut("q") }.menuBarExtraStyle(.menu) } init() { let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true] let accessibilityEnabled = AXIsProcessTrustedWithOptions(options) if accessibilityEnabled == true { print("Accessibility is enabled") } else { print("Accessibility is not enabled. Please enable it in System Preferences") } } } I didn't do any other configuration, and test this app by using the command Command+R, need I set provisioning profile? Please help, thank you.
1
2
870
Mar ’24
Issue with SceneStorage in ViewModifer, but not in View
Hello, Awhile ago I'd refactored my code to have @SceneStorage in a ViewModifier and not on a View. In Xcode 15.3, I see a runtime-only warning: SceneStorage is only for use with SwiftUI App Lifecycle. This will become a fatal error in a future release. Accessing a SceneStorage value outside of being installed on a View. This will always return the default value. Creating a Binding to SceneStorage value outside of being installed on a View. This will result in a constant Binding of the default value and will not update. I'd used a ViewModifier to encapsulate this code. Why is that different than a View? If you are interested you can see an example here: https://github.com/bolsinga/site/blob/ffbedd7fb134675496f529cf62484ceb9b79d360/Sources/Site/Music/UI/ArchiveStorageModifier.swift#L15 Thanks for any tips!
3
0
1.1k
Mar ’24
[tvOS] ScrollView with Text does not scroll
I'm trying to do something so seemingly basic, yet I can't get it to work and I'm flummoxed. In a basic, vanilla SwiftUI app for tvOS, embed a single Text element with a very long string (hundreds of lines) in it: struct ContentView: View { var body: some View { ScrollView(.vertical) { Text(veryLargeString) .focusable() } } } Then fire up the app on tvOS, and it will not scroll. No matter what I do. Pressing arrow keys, swiping fast with my thumb, and nothing. It will not move. Ironically, in the Xcode SwiftUI Preview window—it does scroll, so that's always a fun tease. What I do know is that the focus engine is throwing a few errors, so it's leading me to believe the issue is with how I have the focusable element attached. I'm using a combination of -UIFocusLoggingEnabled YES as well as listening for UIFocusSystem.movementDidFailNotification. Unfortunately since this is SwiftUI, the notification failure and debugging logs aren't really all that actionable. Help appreciated!
2
3
1.2k
Mar ’24
Error: _SwiftData_SwiftUI: one-time initialization function for empty
My App keeps crashing in the background and I don't know why. I'm using SwiftData and SwiftUI. I'm setting up a .backgroundTask like this: import SwiftUI import SwiftData import TipKit @main struct MyAppName: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @State var navManager = NavigationManager.load() @State var alerter: Alerter = Alerter() var sharedModelContainer: ModelContainer = { do { return try ModelContainer(for: DataController.schema, configurations: [DataController.modelConfig]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { SetupView() .accentColor(.myAccentColor) .environment(alerter) .alert(isPresented: $alerter.isShowingAlert) { alerter.alert ?? Alert(title: Text(verbatim: "")) } .task { try? Tips.configure([ .displayFrequency(.immediate), .datastoreLocation(.applicationDefault) ]) } .onAppear { setUpAppDelegate() } } .modelContainer(sharedModelContainer) .backgroundTask(.appRefresh(Const.backgroundAppRefreshId)) { @MainActor in let container = sharedModelContainer await RefreshManager.handleBackgroundVideoRefresh(container) } .environment(navManager) } func setUpAppDelegate() { appDelegate.navManager = navManager } } The RefreshManager.handleBackgroundRefresh(...) goes on to load data and then insert models for them via SwiftData. It only happens occasionally and afaik only in the background. Weirdly enough the issue seems to be there even when I only print something in the background task. Even when I don't schedule/set a background task at all. How can that be? The crashes started in the version that included the .backgroundTask, although perhaps it's related to something else. I'm still trying to further narrow it down. This is the crash report that I'm getting: Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001a1bb98c0 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [809] Triggered by Thread: 0 Thread 0 name: Thread 0 Crashed: 0 libswiftCore.dylib 0x00000001a1bb98c0 _assertionFailure(_:_:file:line:flags:) + 264 (AssertCommon.swift:144) 1 libswiftCore.dylib 0x00000001a1c27d14 swift_unexpectedError + 664 (ErrorType.swift:188) 2 _SwiftData_SwiftUI 0x000000024310cd78 one-time initialization function for empty + 300 (ModelContainer+Extensions.swift:5) 3 libdispatch.dylib 0x00000001ab16add4 _dispatch_client_callout + 20 (object.m:576) 4 libdispatch.dylib 0x00000001ab16c654 _dispatch_once_callout + 32 (once.c:52) 5 _SwiftData_SwiftUI 0x000000024310cdf8 one-time initialization function for empty + 124 (ModelContainer+Extensions.swift:12) 6 libdispatch.dylib 0x00000001ab16add4 _dispatch_client_callout + 20 (object.m:576) 7 libdispatch.dylib 0x00000001ab16c654 _dispatch_once_callout + 32 (once.c:52) 8 _SwiftData_SwiftUI 0x0000000243122170 key path getter for EnvironmentValues.modelContext : EnvironmentValues + 140 (<compiler-generated>:0) 9 libswiftCore.dylib 0x00000001a1ce4628 RawKeyPathComponent._projectReadOnly<A, B, C>(_:to:endingWith:) + 1012 (KeyPath.swift:1701) 10 libswiftCore.dylib 0x00000001a1ce3ddc KeyPath._projectReadOnly(from:) + 1036 (KeyPath.swift:331) 11 libswiftCore.dylib 0x00000001a1ce8348 swift_getAtKeyPath + 24 (KeyPath.swift:2029) 12 SwiftUI 0x00000001a7af4814 EnvironmentBox.update(property:phase:) + 872 (Environment.swift:273) 13 SwiftUI 0x00000001a782a074 static BoxVTable.update(ptr:property:phase:) + 396 (DynamicPropertyBuffer.swift:294) 14 SwiftUI 0x00000001a78297b0 _DynamicPropertyBuffer.update(container:phase:) + 104 (DynamicPropertyBuffer.swift:215) 15 SwiftUI 0x00000001a887fb78 closure #1 in closure #1 in DynamicBody.updateValue() + 104 (DynamicProperty.swift:447) 16 SwiftUI 0x00000001a887fbb8 partial apply for closure #1 in closure #1 in DynamicBody.updateValue() + 28 (<compiler-generated>:0) 17 libswiftCore.dylib 0x00000001a1bcc068 withUnsafeMutablePointer<A, B>(to:_:) + 28 (LifetimeManager.swift:82) 18 SwiftUI 0x00000001a887f9dc closure #1 in DynamicBody.updateValue() + 408 (DynamicProperty.swift:446) 19 SwiftUI 0x00000001a887f5c0 DynamicBody.updateValue() + 712 (DynamicProperty.swift:445) 20 SwiftUI 0x00000001a71e8bf8 partial apply for implicit closure #1 in closure #1 in closure #1 in Attribute.init<A>(_:) + 32 (<compiler-generated>:0) 21 AttributeGraph 0x00000001cbd4c240 AG::Graph::UpdateStack::update() + 512 (ag-graph-update.cc:578) 22 AttributeGraph 0x00000001cbd42f38 AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 424 (ag-graph-update.cc:719) 23 AttributeGraph 0x00000001cbd42810 AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 720 (ag-graph.cc:1429) 24 AttributeGraph 0x00000001cbd423a4 AGGraphGetValue + 228 (AGGraph.mm:701) 25 SwiftUI 0x00000001a887f548 DynamicBody.updateValue() + 592 (DynamicProperty.swift:444) 26 SwiftUI 0x00000001a71e8bf8 partial apply for implicit closure #1 in closure #1 in closure #1 in Attribute.init<A>(_:) + 32 (<compiler-generated>:0) 27 AttributeGraph 0x00000001cbd4c240 AG::Graph::UpdateStack::update() + 512 (ag-graph-update.cc:578) 28 AttributeGraph 0x00000001cbd42f38 AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 424 (ag-graph-update.cc:719) [...] 107 SwiftUI 0x00000001a7cf79fc static App.main() + 132 (App.swift:114) 108 MyAppName 0x0000000100e6d120 static MyAppNameApp.$main() + 52 (MyAppNameApp.swift:0) 109 MyAppName 0x0000000100e6d120 main + 64 110 dyld 0x00000001c67c2d84 start + 2240 (dyldMain.cpp:1298) The report also says key path getter for EnvironmentValues.modelContext, which seems odd. Any idea where I could start to look for the issue? I'm currently just trying things out, pushing them to TestFlight and waiting for crashes to happen. As soon as I can narrow it down further I'll update this.
7
2
2.2k
Mar ’24
Sonoma 14.4.1 macOS Menu Issues
Sonoma 14.4.1 (did not test on 14.4) Xcode 15.3 New Project macOS Document App Run View menu has "Enter Full Screen" Do Command-N View menu does not have "Enter Full Screen" May need to open and close a few windows. import SwiftUI @main struct testApp: App { var body: some Scene { DocumentGroup(newDocument: testDocument()) { file in ContentView(document: file.$document) } .commands { CommandGroup(replacing: CommandGroupPlacement.saveItem) { } } } } File menu Open Recent becomes NSMenuItem
3
0
583
Mar ’24
SwiftUI fileImporter vs dropDestination logic
If I drag something into my SwiftUI Mac app the .dropDestination gets an array of URLs that I can do with what I want. If I use .fileImporter to get an identical array of URLs I should wrap start/stop securityScopedResource() calls around each URL before I do anything with it. Can anyone explain the logic behind that? Is there some reason I'm not seeing? It is especially annoying in that the requirement for security scoping also doesn't exist if I use an NSOpenPanel instead of .fileImporter.
5
0
1.4k
Mar ’24
Accessibility : Full keyboard access with scroll view in swiftui
I have checked almost all previous question related to my query but did not find my solution. I'm facing issue with Full keyboard access accessibility when integrate it with scrollview. Inside scrollview textfield and secure textfield are accessible with "tab" key but other component like buttons are not accessible using "tab" key. but when I remove scrollview all elements are accessible with "tab" key. Even in system installed iOS Apps they don't support scrollview with tab button, I have analysed apple documentation regarding this but did not find specific to this. Does anyone have idea regarding this kind of behaviour?
1
1
848
Mar ’24
How to resolve SwiftUI.DynamicProperty on MainActor compiler warning on 6.0?
Hi! I'm running into a warning from a SwiftUI.DynamicProperty on a 6.0 development build (swift-6.0-DEVELOPMENT-SNAPSHOT-2024-03-26-a). I am attempting to build a type (conforming to DynamicProperty) that should also be MainActor. This type with also need a custom update function. Here is a simple custom wrapper (handwaving over the orthogonal missing pieces) that shows the warning: import SwiftUI @MainActor struct MainProperty: DynamicProperty { // Main actor-isolated instance method 'update()' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode @MainActor func update() { } } Is there anything I can do about that warning? Does the warning correctly imply that this will be a legit compiler error when 6.0 ships? I can find (at least) two examples of types adopting DynamicProperty from Apple that are also MainActor: FetchRequest and SectionedFetchRequest. What is confusing is that both FetchRequest^1 and SectionedFetchRequest^2 explicitly declare their update method to be MainActor. Is there anything missing from my Wrapper declaration that can get me what I'm looking for? Any more advice about that? Thanks!
4
1
1.1k
Apr ’24
iOS ImageRenderer Unable to localize text correctly Bug
A simple view has misaligned localized content after being converted to an image using ImageRenderer. This is still problematic on real phone and TestFlight I'm not sure what the problem is, I'm assuming it's an ImageRenderer bug. I tried to use UIGraphicsImageRenderer, but the UIGraphicsImageRenderer captures the image in an inaccurate position, and it will be offset resulting in a white border. And I don't know why in some cases it encounters circular references that result in blank images. "(1) days" is also not converted to "1 day" properly.
4
1
933
Apr ’24
Best Way to Support Different Devices in SwiftUI?
Hi, I have pretty much finished my app's layout but realized I needed to scale it for different devices. I have read online that hardcoding values (esp in frames) is a big no-no, and GeometryReader should be heavily utilized. Also was recommended ViewThatFits. The problem is, I want the app to look the exact same across all devices. What is the best way to get started? Also, when testing, do I only have to test on an iPad and iPhone or are the dimensions significantly different amongst each class of devices?
1
0
603
Apr ’24
SwiftUI/SwiftData view deep in the hierarchy looses model container
iPad mini device with iPadOS 17.4.1. I get this failure on iPad mini device exclusively. I have universal app and I doesn't get this error neither on iPhone or any simulator or macOS. I tried to reset the iPad, still getting the error. The error happens when I send the app to background from the particular app screen. Here is the error: error: Store failed to load. <NSPersistentStoreDescription: 0x3004b4bd0> (type: SQLite, url: file:///dev/null) with error = Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred." UserInfo={NSLocalizedFailureReason=The configuration named 'default' does not contain any entities.} with userInfo { NSLocalizedFailureReason = "The configuration named 'default' does not contain any entities."; } What error says is that it loaded the store from file:///dev/null, which is wrong. Basically it looses the model container which is added via modelContaner modificator to the root view. The error get caused particularly by the @Environment(\.modelContext) private var modelContext call in the view on which the failure occurs. This view is deep in the view hierarchy, and it get's created in the navigationDestination block. I fixed the error by supplying modelContainer one more time right on the view: .navigationDestination(for: File.self) { file in FileEditor(file: file) .modelContainer(FolderService.modelContainer) } I wonder, why can it loose the model container which is supplied on the root view?
4
0
919
Apr ’24
VisionOS NavigationStack background cannot be removed?
I have a simple example to demonstrate... struct MyView: View { var body: some View { Text("WOW") } } struct MyOtherView: View { var body: some View { NavigationStack { Text("WOW") } } } On VisionOS, MyOtherView has a glass background effect that cannot be disabled. glassBackgroundEffect(displayMode: .never) .background(.clear), .foregroundColor(.clear), none of them work. I then resorted to the SwiftUIIntrospect package to try set .clear on various child objects of the NavigationStack but nothing is working. I am in control of my own glass containers. I have a couple with space between them, but with the NavigationStack it sets a background behind both of them ruining the effect. This is what MyOtherView renders as: I'm looking for it to be completely transparent except the text. Like the below layout. For now I will have to roll my own navigation.
4
2
927
Apr ’24
Infinite loop refreshing view with EnvironmentValue
Adding environment value openURL or dismiss to a View in a NavigationStack, without even using it, causes an infinite refresh loop. What doesn't work: a) struct ViewA: View { @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { ViewB() } } } struct ViewB: View { @Environment(\.openURL) var openURL var body: some View { NavigationLink("Next", value: 1) .navigationDestination(for: Int.self, destination: itemView) } func itemView(_ item: Int) -> some View { Text("Item \(item)") } } Prints ViewB: _openURL changed. infinitely. b) Passing the path to ViewB and appending the value with a Button What works: a) .navigationDestination(for: Int.self) { Text("Item \($0)") } Prints ViewB: @self, @identity, _openURL changed. ViewB: @self, _openURL changed. ViewB: _openURL changed. (3 times) b) Handling the destination on ViewA, which is not ideal for my use case. Prints ViewB: @self, @identity, _openURL changed. ViewB: _openURL changed. (5 times) While the workaround would work, it is still unclear how the environment value can cause the freeze (and eventual crash). Also that passing a function as parameter fails, while providing the destination in place does not. The code is stripped down to the minimal reproducible version. Any thoughts?
3
9
877
Apr ’24
SwiftData make my app very slow
Hello, I have been working on SwiftData since a month now and i found very weird that every time i update a data inside a SwiftData model my app became very slow. I used the instrument if something was wrong, and i see memory increasing without releasing. My app have a list with check and unchecked elements (screeshot below). I just press check and unchecked 15 times and my memory start from 149mb to 361mb (screenshots below). For the code i have this model. final class Milestone: Identifiable { // ********************************************************************* // MARK: - Properties @Transient var id = UUID() @Attribute(.unique) var uuid: UUID var text: String var goalId: UUID var isFinish: Bool var createdAt: Date var updatedAt: Date var goal: Goal? init(from todoTaskResponse: TodoTaskResponse) { self.uuid = todoTaskResponse.id self.text = todoTaskResponse.text self.goalId = todoTaskResponse.goalId self.isFinish = todoTaskResponse.isFinish self.createdAt = todoTaskResponse.createdAt self.updatedAt = todoTaskResponse.updatedAt } init(uuid: UUID, text: String, goalId: UUID, isFinish: Bool, createdAt: Date, updatedAt: Date, goal: Goal? = nil) { self.uuid = uuid self.text = text self.goalId = goalId self.isFinish = isFinish self.createdAt = createdAt self.updatedAt = updatedAt self.goal = goal } } For the list i have var milestonesView: some View { ForEach(milestones) { milestone in MilestoneRowView(task: milestone) { milestone.isFinish.toggle() } .listRowBackground(Color.backgroundComponent) } .onDelete(perform: deleteMilestone) } And this is the cell struct MilestoneRowView: View { // ********************************************************************* // MARK: - Properties var task: Milestone var action: () -> Void init(task: Milestone, action: @escaping () -> Void) { self.task = task self.action = action } var body: some View { Button { action() } label: { HStack(alignment: .center, spacing: 8) { Image(systemName: task.isFinish ? "checkmark.circle.fill" : "circle") .font(.title2) .padding(3) .contentShape(.rect) .foregroundStyle(task.isFinish ? .gray : .primary) .contentTransition(.symbolEffect(.replace)) Text(task.text) .strikethrough(task.isFinish) .foregroundStyle(task.isFinish ? .gray : .primary) } .foregroundStyle(Color.backgroundComponent) } .animation(.snappy, value: task.isFinish) } } Does someone have a idea? Thanks
1
0
1.2k
Apr ’24
SwiftUI chart - take screenshot of the chart view on macOS
Hello all, if I enable the .chartScrollableAxes(.horizontal) and .chartXVisibleDomain(length: length) for a chart view to zoom in the screenshot of the view misses the graphs. I use this extension: `extension View { @MainActor func snapshot() { let renderer = ImageRenderer(content: self) if let exportImage = renderer.nsImage { let pasteboard = NSPasteboard.general pasteboard.clearContents() pasteboard.writeObjects([exportImage]) } } }` The screenshot is taken with: Button("Snap") { let view = ChartView(text: $statusText, length: $chartLength) .padding() .frame(width: 1500, height: 500) view.snapshot() } If I omit .chartScrollableAxes(.horizontal) the snapshot is ok and the graphs are visible in the image but then a zoom is not possible and the whole range is shown. Any ideas?
1
1
700
Apr ’24