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

Inconsistent subviews redrawing in LazyVStack
Hello Apple forum ! I spotted a weird behaviour with LazyVStack in a ScrollView. I understand that it loads its views only once upon appearance unlinke VStack that loads everything in one shot. What I noticed also, it seems to reload its views sometimes when scrolling back up to earlier loaded views. The thing is, it isn't always the case. struct LazyVStackTest: View { var body: some View { ScrollView { LazyVStack { ForEach(0..<1000, id: \.self) { _ in // if true { MyText() // } } } } } struct MyText: View { var body: some View { let _ = Self._printChanges() HStack { Text("hello") } } } } If we consider the code above on XCode 26 beta 7 on an iOS 26 or iOS 18.2 simulator. Scroll to the bottom : you'll see one "LazyVStackTest.MyText: @self changed" for each row. Then scroll back up to the top, we'll see again the same message printed multiple times. --> So I gather from this that LazyVStack not only loads lazily but also removes old rows from memory & recreates them upon reappearance. What I don't get however is that if you uncomment the "if true" statement, you won't see the reloading happening. And I have absolutely no clue as to why 😅 If someone could help shed some light on this weird behaviour, it would be greatly appreciated ^^ PS : the issue is also present with XCode 16.2 but at a deeper lever (ex: if we embed another custom View "MyText2" inside "MyText", the reloading is in "MyText2" & not "MyText")
0
0
131
6d
TextEditor Problem Or Me?
When using SwiftUI's TextEditor, the application crashes immediately on launch. This occurs even in a brand new project with the simplest usage. If I remove the TextEditor, the application runs normally. Environment: OS: macOS 15.6.1 Xcode: 16.4 SDK: macOS 14 (and also tried with macOS 15 SDK) Steps to Reproduce: Create a new SwiftUI macOS App project. Replace ContentView with the following code: import SwiftUI struct ContentView: View { @State private var text = "114514" var body: some View { TextEditor(text: $text) } } Run the app. Expected Result: The app should display a working TextEditor. Actual Result: The app immediately crashes, and the debugger shows a Metal assertion error. If I remove the TextEditor, the app works fine. Screenshot: Additional Notes: This issue did not occur on macOS 14 / Xcode 15.4. It reproduces even in an empty project. Possibly related to SwiftUI/Metal integration on macOS 15.6.1. 這樣寫更專業、清楚,Apple 工程師能快速重現和定位問題。 如果你要用中文回報也可以,我能幫你翻譯。
Topic: UI Frameworks SubTopic: SwiftUI
2
0
86
1w
NavigationStack path is being reset in NavigationSplitView details columns
I'm building a SwiftUI app for iPad using a NavigationSplitView as the navigation root. Below is a simplified version of the app's navigation. There are a Home Page and a Settings Page, each with its own NavigationStack. The page that appears in the detail column depends on the sidebar's selection value. The issue I'm facing is that when I navigate deeply into the Home Page's NavigationStack (e.g., to a Home Page Child view), switch to the Settings Page, and then switch back to the Home Page, the Home Page's navigation path has been reset to [] and the previous state is lost. The same issue occurs if I navigate deeply into the Settings Page (e.g., to a Settings Page Child view), switch to the Home Page, and then return to the Settings Page: the navigation state for the Settings Page is lost, and it reverts to the root of the NavigationStack. Why is this happening and how can I fix it so that switching pages in the sidebar doesn't reset the NavigationStack of each individual page in the detail column? Thank you. struct ContentView: View { @State var selection: String? @State var firstPath = [String]() @State var secondPath = [String]() var body: some View { NavigationSplitView { List(selection: $selection) { Text("Home") .tag("home") Text("Settings") .tag("settings") } } detail: { if selection == "home" { HomePage(path: $firstPath) } else { SettingsPage(path: $secondPath) } } } } struct HomePage: View { @Binding var path: [String] var body: some View { NavigationStack(path: $path) { NavigationLink("Home Page", value: "Home") .navigationDestination(for: String.self) { _ in Text("Home Page Child") } } } } struct SettingsPage: View { @Binding var path: [String] var body: some View { NavigationStack(path: $path) { NavigationLink("Settings Page", value: "Settings") .navigationDestination(for: String.self) { _ in Text("Settings Page Child") } } } } #Preview { ContentView() }
0
0
226
1w
SwiftUI TextField with optional value working for @State but not @Binding properties
I've encountered a potential bug where a TextField connected to an optional value (not a string) works as expected when bound to a @State property, but won't update a @Binding property. Here is some example code import SwiftUI struct ContentView: View { @Binding var boundValue: Double? @State private var stateValue: Double? = 55 var body: some View { TextField("Bound value", value: $boundValue, format: .number) Text("\(boundValue ?? .nan)") TextField("State value", value: $stateValue, format: .number) Text("\(stateValue ?? .nan)") } } #Preview { ContentView(boundValue: .constant(42.00)) } It's as though the optional value stored externally is preventing the value updating. Can anyone confirm whether this is intentional, or a bug? This is in Xcode 26b6, on macOS Tahoe 26b8, but from this query it looks like the problem has existed for years.
Topic: UI Frameworks SubTopic: SwiftUI
8
0
311
1w
UtilityWindow can't read @FocusedValue of main scene
According to the UtilityWindow documentation: • They receive FocusedValues from the focused main scene in an application, similar to commands in the main menu, which can be used to display information on the active content as the user focuses on different scenes. This makes me think that any UtilityWindow, even across Scenes, should always receive @FocusedValues from the currently focused window of any scene. However, the following code doesn't quite work: @Observable class Info: Identifiable { let id = UUID() } struct ExampleApp: App { var body: some Scene { WindowGroup { ContentView() // Inside, it uses .focusedSceneValue(info) } UtilityWindow("Test") { UtilityWindowContent() } } } struct UtilityWindowContent: View { @FocusedValue(Info.self) var info var body: some View { Text(info?.id ?? "<nil>") // This always shows "<nil>" } } Here's some annotated screenshots of what's happening in a project: Menu bar commands do work with the same setup: As a workaround, attempting to use @FocusedValue in the App struct works, but as a result, the value appears to instantiate multiple times in the background, and they re-instantiate with every focus change. The @FocusedValue variable gets the correct instance, but it's needlessly initializing others in the background. This is on macOS 26.0 Tahoe Beta 8 (25A5349a).
0
0
94
1w
Charts SectorMark causing app to crash
Anytime I have 1 item, then add another, the app crashes with the following error: Swift/IntegerTypes.swift:8835: Fatal error: Double value cannot be converted to Int because it is either infinite or NaN I'm not working with Int values though, so I'm not sure why this is happening. It's also not point me towards any specific line. I've printed out all of the values being used for the chart and none of them are showing as infinite or NaN. The data being used is created in a View. @State private var pieChartData: [PieChartDataPoint] = [] Then in the onAppear and onChange its gets loaded using the following function: func getPieChartDataPoints() -> [PieChartDataPoint] { self.map({ PieChartDataPoint(label: $0.name, value: $0.monthlyAmount()) }) } That's an extension on a SwiftData model type I have called Recurring. @Model final class Recurring { var id = UUID() enum Kind: String, CaseIterable, Codable { case income = "Income" case bill = "Bill" func plural() -> String { switch self { case .income: "Income" case .bill: "Bills" } } } enum Frequency: String, CaseIterable, Codable, Identifiable { var id: Frequency { self } case weekly = "Weekly" case biweekly = "Biweekly" case monthly = "Monthly" case quarterly = "Quarterly" case annually = "Annually" } var name: String = "" var kind: Kind = Kind.income var frequency: Frequency = Frequency.biweekly var amount: Double = 0 init(name: String, kind: Kind, frequency: Frequency, amount: Double) { self.name = name self.kind = kind self.frequency = frequency self.amount = amount } func amount(from cycle: Cycle) -> Double { switch cycle { case .weekly: monthlyAmount() * 12 / 52 case .biweekly: monthlyAmount() * 12 / 26 case .monthly: monthlyAmount() } } func monthlyAmount() -> Double { switch frequency { case .weekly: amount * 52 / 12 case .biweekly: amount * 26 / 12 case .monthly: amount case .quarterly: amount * 4 / 12 case .annually: amount / 12 } } } Here is the DataPoint structure. struct PieChartDataPoint: Identifiable, Equatable { var id = UUID() var label: String var value: Double } Finally here is the chart. Chart(sorted, content: { dataPoint in SectorMark( angle: .value(dataPoint.label, getValue(from: dataPoint)), innerRadius: 50, angularInset: 5 ) .foregroundStyle(by: .value("Label", dataPoint.label)) .cornerRadius(10) .opacity(getSectorMarkOpacity(for: dataPoint)) }) .scaledToFill() .chartLegend(.hidden) .chartAngleSelection(value: $chartSelection) .onChange(of: chartSelection, checkSelection) For testing purposes, I have removed all of the modifiers and only had a simple SectorMark in the Chart, however, that was still crashing. Does anyone know why this is happening?
1
0
54
1w
SwiftUI drag & drop: reliable cancellation
Summary In a SwiftUI drag-and-drop flow, the only robust way I’ve found to detect cancellation (user drops outside any destination) is to rely on the NSItemProvider created in .onDrag and run cleanup when it’s deallocated, via a custom onEnded callback tied to its lifecycle. On iOS 26, the provider appears to be deallocated immediately after .onDrag returns (unless I keep a strong reference), so a deinit/onEnded-based cancel hook fires right away and no longer reflects the true end of the drag session. I’d like to know: 1. Is there a supported, reliable way to detect when a drag ends outside any drop target so I can cancel and restore the source row? 2. Is the iOS 26 NSItemProvider deallocation timing a bug/regression or intended behavior? Minimal SwiftUI Repro This example shows: • creating a custom NSItemProvider subclass with an onEnded closure • retaining it to avoid immediate dealloc (behavior change on iOS 26) • using performDrop to mark the drag as finished import SwiftUI import UniformTypeIdentifiers final class DragProvider: NSItemProvider { var onEnded: (() -> Void)? deinit { // Historically: called when the system drag session ended (drop or cancel). // On iOS 26: can fire immediately after .onDrag returns unless the provider is retained. onEnded?() } } struct ContentView: View { struct Item: Identifiable, Equatable { let id = UUID(); let title: String } @State private var pool: [Item] = (1...4).map { .init(title: "Option \($0)") } @State private var picked: [Item] = [] @State private var dragged: Item? @State private var dropFinished: Bool = true @State private var activeProvider: DragProvider? // Retain to avoid immediate dealloc private let dragType: UTType = .plainText var body: some View { HStack(spacing: 24) { // Destination list (accepts drops) VStack(alignment: .leading, spacing: 8) { Text("Picked").bold() VStack(spacing: 8) { ForEach(picked) { item in row(item) } } .padding() .background(RoundedRectangle(cornerRadius: 8).strokeBorder(.quaternary)) .onDrop(of: [dragType], delegate: Dropper( picked: $picked, pool: $pool, dragged: $dragged, dropFinished: $dropFinished, activeProvider: $activeProvider )) } .frame(maxWidth: .infinity, alignment: .topLeading) // Source list (draggable) VStack(alignment: .leading, spacing: 8) { Text("Pool").bold() VStack(spacing: 8) { ForEach(pool) { item in row(item) .onDrag { startDrag(item) return makeProvider(for: item) } preview: { row(item).opacity(0.9).frame(width: 200, height: 44) } .overlay( RoundedRectangle(cornerRadius: 8) .fill(item == dragged ? Color(.systemBackground) : .clear) // keep space ) } } .padding() .background(RoundedRectangle(cornerRadius: 8).strokeBorder(.quaternary)) } .frame(maxWidth: .infinity, alignment: .topLeading) } .padding() } private func row(_ item: Item) -> some View { RoundedRectangle(cornerRadius: 8) .strokeBorder(.secondary) .frame(height: 44) .overlay( HStack { Text(item.title); Spacer(); Image(systemName: "line.3.horizontal") } .padding(.horizontal, 12) ) } // MARK: Drag setup private func startDrag(_ item: Item) { dragged = item dropFinished = false } private func makeProvider(for item: Item) -> NSItemProvider { let provider = DragProvider(object: item.id.uuidString as NSString) // NOTE: If we DO NOT retain this provider on iOS 26, // its deinit can run immediately (onEnded fires too early). activeProvider = provider provider.onEnded = { [weak self] in // Intended: run when system drag session ends (drop or cancel). // Observed on iOS 26: may run too early unless retained; // if retained, we lose a reliable "session ended" signal here. DispatchQueue.main.async { guard let self else { return } if let d = self.dragged, self.dropFinished == false { // Treat as cancel: restore the source item if !self.pool.contains(d) { self.pool.append(d) } self.picked.removeAll { $0 == d } } self.dragged = nil self.dropFinished = true self.activeProvider = nil } } return provider } // MARK: DropDelegate private struct Dropper: DropDelegate { @Binding var picked: [Item] @Binding var pool: [Item] @Binding var dragged: Item? @Binding var dropFinished: Bool @Binding var activeProvider: DragProvider? func validateDrop(info: DropInfo) -> Bool { dragged != nil } func performDrop(info: DropInfo) -> Bool { guard let item = dragged else { return false } if let idx = pool.firstIndex(of: item) { pool.remove(at: idx) } picked.append(item) // Mark drag as finished so provider.onEnded won’t treat it as cancel dropFinished = true dragged = nil activeProvider = nil return true } } } Questions Is there a documented, source-side callback (or best practice) to know the drag session ended without any performDrop so we can cancel and restore the item? Has the NSItemProvider deallocation timing (for the object returned from .onDrag) changed intentionally on iOS 26? If so, what’s the recommended replacement signal? Is there a SwiftUI-native event to observe the end of a drag session that doesn’t depend on the provider’s lifecycle?
0
1
83
1w
WebView makes website content unaccessible on the top/bottom edges
I'm being faced with an issue when using SwiftUI's WebView on iOS 26. In many websites, the top/bottom content is unaccessible due to being under the app's toolbars. It feels like the WebView doesn't really understand the safe areas where it's being shown, because the content should start right below the navigation bar, and only when the user scrolls down, the content should move under the bar (but it's always reachable if the users scroll back up). Here's a demo of the issue: Here's a 'fix' by ensuring that the content of the WebView never leaves its bounds. But as you can see, it feels out of place on iOS 26 (would be fine on previous OS versions if you had a fully opaque toolbar): Code: struct ContentView: View { var body: some View { NavigationStack { WebView(url: URL(string: "https://apple.com")).toolbar { ToolbarItem(placement: .primaryAction) { Button("Top content covered, unaccessible.") {} } } } } } Does anyone know if there's a way to fix it using some sort of view modifier combination or it's just broken as-is?
6
1
152
1w
PasteButton asks for permissions every time
Hi, i'm using the PasteButton component to paste content from clipboard. On the docs it says that the PasteButton will handle internally permissions and will not present the prompt. But in my case seems to be not true. I removed all the occurrencies of UIPasteboard.general.string since i read that this will cause the prompt to appear. Also as you can see on the code below i'm not doing fancy or weird things, even with the base component this behaviour is still there. PasteButton(payloadType: String.self) { strings in if let first = strings.first { print("clipboard text: \(first)") } } I can see other apps using this paste button without asking for permissions every time, but i cannot see any issue in my code.
0
0
14
1w
SwiftUI app crash with __swift_instantiateConcreteTypeFromMangledName
Hello, I am experiencing a crash in a SwiftUI app. It happens when I place multiple views inside a ScrollView. The crash occurs only on a physical device (it does not reproduce in the Simulator). It happens during runtime, seemingly while SwiftUI is updating or laying out the view hierarchy. I have not been able to determine the exact cause. I am attaching a text file with the entire backtrace from LLDB. swiftui_crash_backtrace Is this a known SwiftUI issue? Any recommendations on how to further investigate or work around it? Any help or suggestions would be appreciated. Xcode 16.3 / iOS 18.6.2 Thank you!
1
0
86
1w
iOS 26 Beta bug - keyboard toolbar with bottom safe area inset
Hello! I have experienced a weird bug in iOS 26 Beta (8) and previous beta versions. The safe area inset is not correctly aligned with the keyboard toolbar on real devices and simulators. When you focus a new textfield the bottom safe area is correctly placed aligned the keyboard toolbar. On real devices the safe area inset view is covered slightly by the keyboard toolbar, which is even worse than on the simulator. Here's a clip from a simulator: Here's the code that reproduced the bug I experienced in our app. #Preview { NavigationStack { ScrollView { TextField("", text: .constant("")) .padding() .background(Color.secondary) TextField("", text: .constant("")) .padding() .background(Color.green) } .padding() .safeAreaInset(edge: .bottom, content: { Color.red .frame(maxWidth: .infinity) .frame(height: 40) }) .toolbar { ToolbarItem(placement: .keyboard) { Button {} label: { Text("test") } } } } }
0
6
237
1w
SwiftUI TextField input is super laggy for SwiftData object
have a SwiftUI View where I can edit financial transaction information. The data is stored in SwiftData. If I enter a TextField element and start typing, it is super laggy and there are hangs of 1-2 seconds between each input (identical behaviour if debugger is detached). On the same view I have another TextField that is just attached to a @State variable of that view and TextField updates of that value work flawlessly. So somehow the hangs must be related to my SwiftData object but I cannot figure out why. This used to work fine until a few months ago and then I could see the performance degrading. I have noticed that when I use a placeholder variable like @State private var transactionSubject: String = "" and link that to the TextField, the performance is back to normal. I am then using .onSubmit { self.transaction.subject = self.transactionSubject } to update the value in the end but this again causes a 1 s hang. :/ Below the original code sample with some unnecessary stuff removed: struct EditTransactionView: View { @Environment(\.modelContext) var modelContext @Environment(\.dismiss) var dismiss @State private var testValue: String = "" @Bindable var transaction: Transaction init(transaction: Transaction) { self.transaction = transaction let transactionID = transaction.transactionID let parentTransactionID = transaction.transactionMasterID _childTransactions = Query(filter: #Predicate<Transaction> {item in item.transactionMasterID == transactionID }, sort: \Transaction.date, order: .reverse) _parentTransactions = Query(filter: #Predicate<Transaction> {item in item.transactionID == parentTransactionID }, sort: \Transaction.date, order: .reverse) print(_parentTransactions) } //Function to keep text length in limits func limitText(_ upper: Int) { if self.transaction.icon.count > upper { self.transaction.icon = String(self.transaction.icon.prefix(upper)) } } var body: some View { ZStack { Form{ Section{ //this one hangs TextField("Amount", value: $transaction.amount, format: .currency(code: Locale.current.currency?.identifier ?? "USD")) //this one works perfectly TextField("Test", text: $testValue) HStack{ TextField("Enter subject", text: $transaction.subject) .onAppear(perform: { UITextField.appearance().clearButtonMode = .whileEditing }) Divider() TextField("Select icon", text: $transaction.icon) .keyboardType(.init(rawValue: 124)!) .multilineTextAlignment(.trailing) } } } .onDisappear(){ if transaction.amount == 0 { // modelContext.delete(transaction) } } .onChange(of: selectedItem, loadPhoto) .navigationTitle("Transaction") .navigationBarTitleDisplayMode(.inline) .toolbar{ Button("Cancel", systemImage: "trash"){ modelContext.delete(transaction) dismiss() } } .sheet(isPresented: $showingImagePickerView){ ImagePickerView(isPresented: $showingImagePickerView, image: $image, sourceType: .camera) } .onChange(of: image){ let data = image?.pngData() if !(data?.isEmpty ?? false) { transaction.photo = data } } .onAppear(){ cameraManager.requestPermission() setDefaultVendor() setDefaultCategory() setDefaultGroup() } .sheet(isPresented: $showingAmountEntryView){ AmountEntryView(amount: $transaction.amount) } } } }
2
0
111
1w
Blurred selected button on tvOS
The following code shows that a selected button in a list gots blurred if a glass effect is applied to the list. This happens if the button style is plain or glass. It does not happen if the button style is bordered. Is this a wanted documented behavior or is this a bug? struct ContentView: View { @State private var items = [ "Item 1", "Item 2", "Item 3", "Item 4"] var body: some View { ZStack { Image(systemName: "globe") .resizable() List(items, id: \.self) { item in Button(action: {}, label: { Text(item) }) } .padding() .glassEffect(in: Rectangle()) } } }
2
0
52
1w
iOS 26 Beta - AppStore.showManageSubscriptions() Shows Empty View Before StoreKit Sheet
Environment iOS Version: iOS 26 Beta 8 Xcode Version: iOS 26 Beta 6 StoreKit: StoreKit 2 Description When calling AppStore.showManageSubscriptions(in:) on iOS 26 beta, I'm experiencing an unusual presentation behavior that wasn't present in earlier versions. An empty/blank view appears first Then the actual StoreKit manage subscriptions sheet appears on top When dismissing the StoreKit sheet, it closes properly But then I have to dismiss the empty view underneath as well This creates a poor user experience showing double sheets. Code Sample @MainActor func showManageSubscriptions() { guard let scene = UIApplication.shared.connectedScenes .first(where: { $0 is UIWindowScene }) as? UIWindowScene else { return } Task { do { try await AppStore.showManageSubscriptions(in: scene) } catch { // Handle error } } } Expected Behavior The StoreKit manage subscriptions sheet should present directly without any intermediate empty view, as it did in previous iOS versions. Actual Behavior An empty view layer appears between my app and the StoreKit sheet, requiring users to dismiss twice. Questions Is anyone else experiencing this issue with iOS 26 beta? Is this a known beta issue that will be addressed? Are there any recommended workarounds while waiting for a fix?
3
0
24
1w
Keyboard dismissal not animated
Hello, I’ve encountered what seems to be a bug with the keyboard dismissal animation on iOS 26.0 Beta (25A5349a), Xcode Version 26.0 beta 5 (17A5295f). When dismissing the keyboard from a SwiftUI TextField using @FocusState, the keyboard does not animate downward as expected. Instead, it instantly disappears, which feels jarring and inconsistent with system behavior. I am attaching a short video demonstrating the issue. Below is the minimal reproducible code sample: // // ContentView.swift // TestingKeyboardDismissal // // Created by Sasha Morozov on 27/08/25. // import SwiftUI struct ContentView: View { @State private var text: String = "" @FocusState private var isFocused: Bool var body: some View { ZStack { Color.clear.ignoresSafeArea() VStack(spacing: 20) { TextField("Enter text here...", text: $text) .textFieldStyle(.roundedBorder) .focused($isFocused) .padding(.horizontal) HStack { Button("Focus") { isFocused = true } .buttonStyle(.borderedProminent) Button("Unfocus") { isFocused = false } .buttonStyle(.bordered) } } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) .padding() } .ignoresSafeArea(.keyboard, edges: .bottom) } } #Preview { ContentView() } Steps to reproduce: Run** the app on iOS 26.0 beta 5 (17A5295f). Tap Focus → keyboard appears as expected. Tap Unfocus → keyboard disappears instantly without the usual slide-down animation. Expected result: Keyboard should animate smoothly downwards when dismissed. Actual result: Keyboard instantly vanishes without animation. p.s. we should be really able to upload videos here for demostration
2
1
110
1w
Is realtime multidevice persistence possible using SwiftData?
I really enjoyed using SwiftData for persistence until I found out that the CloudKit integration ensures changes are only eventually consistent, and that changes can propagate to other devices after as long as minutes, making it useless for any feature that involves handoff between devices. Devastating news but I guess it’s on me for nrtfm. I may try my hand at a custom model context DataStore integrating Powersync, but that’s a whole trip and before I embark on it I was wondering if anyone had suggestions for resolving this problem in a simple and elegant manager that allows me to keep as much of the machinery within Apple’s ecosystem as possible, while ensure reliable “live” updates to SwiftData stores on all eligible devices.
2
0
165
1w
ManipulationComponent + Warning messages in RealityView
Hi guys! I wanted to study this new ManipulationComponent(), but I keep getting a warning that I don’t understand, even in a very simple scenario. i don't have any collisions just binding the Manipulation the warning message is : ** Entity returned from EntityWrapper.makeEntity(context:) was already parented to another entity. This is not supported and may lead to unexpected behavior. SwiftUI adds entities to internally-managed entity hierarchies.** RealityView { content, attachments in if let loadedModel = try? await Entity(named: "cloud_glb", in: realityKitContentBundle) { content.add(loadedModel) loadedModel.components.set(ManipulationComponent()) } Thanks !
1
0
87
1w
How to Detect Key + Modifier Combinations at Runtime in SwiftUI on iOS (Without Using .keyboardShortcut)?
In my SwiftUI iOS app, I need to detect which key (and modifier flags – Command, Option, Shift, Control) a user presses, but I don't want to pre-register them using .keyboardShortcut(_:modifiers:). My use case is that keyboard shortcuts are user-configurable, so I need to capture the actual key + modifier combination dynamically at runtime and perform the appropriate action based on the user’s settings. Questions: What is the recommended way to detect arbitrary key + modifier combinations in SwiftUI on iOS? Is there a SwiftUI-native solution for this, or should I rely on UIPressesEvent and wrap it with UIViewControllerRepresentable? If UIKit bridging is necessary, what is the cleanest pattern for integrating this with SwiftUI views (e.g., Buttons)? Any official guidance or best practices would be greatly appreciated!
1
0
123
1w