Post

Replies

Boosts

Views

Activity

How do you autoscroll a ScrollView during a DragGesture on macOS?
In SwiftUI for macOS, when implementing a DragGesture inside a ScrollVIew, how can I implement auto-scrolling when the mouse is not actively moving? In AppKit, this would normally be done with a periodic event so that auto-scrolling continues to take place even if the user isn't actively moving the mouse. This is essential behaviour when implementing something like a drag-to-select gesture. NSView.autoscroll(with: NSEvent) -> Bool Is there anything in SwiftUI or ScrollView to accomplish this behaviour?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
0
0
116
1w
On macOS, what is the appropriate way to disable the sidebar material in a NavigationSplitView?
If you create a NavigationSplitView, then the sidebar is automatically adorned with a sidebar material effect. This affects the views background as well as any controls that are in the view. What is the correct way to disable this behaviour so that I can use a NavigationSplitView without the material effects being applied? The best I've come up with so far is to explicitly set the background on the sidebar but I'm curious if that's the correct way or I'm just getting lucky. struct ContentView: View { var body: some View { NavigationSplitView { // This works, but is it correct? SidebarView() .background(.windowBackground) } detail: { DetailView() } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
4
0
109
1w
In SwiftUI for macOS, how can you detect if a view or any ancestor is "hidden"?
Given a View in SwiftUI for macOS, how can I tell if that view is hidden either because it, or any of its ancestor's opacity is 0.0 or the .hidden modifier has been applied? Presumably I can manually do this with an Environment value on the ancestor view, but I'm curious if this can be done more idiomatically. An example use case: I have views that run long-running Tasks via the .task(id:) modifier. These tasks only need to be running if the View itself is visible to the user. When the View is hidden, the task should stop. When the View reappears, the Task should restart. This happens automatically when Views are created and destroyed, but does not happen when a view is only hidden.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
2
0
68
1w
How do you compute backing pixel alignment in SwiftUI's `Layout`?
When performing custom layout in AppKit, it's essential that you pixel align frames using methods like backingAlignedRect. The alignment differs depending on the backingScaleFactor of the parent window. When building custom Layouts in SwiftUI, how should you compute the alignment of a subview.frame in placeSubviews() before calling subview.place(...)? Surprisingly, I haven't seen any mention of this in the WWDC videos. However, if I create a Rectangle of width 1px and then position it on fractional coordinates, I get a blurry view, as I would expect. Rounding to whole numbers works, but on Retina screens you should be able to round to 0.5 as well. func placeSubviews( in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Void ) { // This should be backing aligned based on the parent window's backing scale factor. var frame = CGRect( x: 10.3, y: 10.8, width: 300.6, height: 300.1 ) subview.place( at: frame.origin, anchor: .topLeading, proposal: ProposedViewSize(frame.size) ) }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
1
0
49
1w
How do you observe the count of records in a Swift Data relationship?
What is the correct way to track the number of items in a relationship using SwiftData and SwiftUI? Imagine a macOS application with a sidebar that lists Folders and Tags. An Item can belong to a Folder and have many Tags. In the sidebar, I want to show the name of the Folder or Tag along with the number of Items in it. I feel like I'm missing something obvious within SwiftData to wire this up such that my SwiftUI views correctly updated whenever the underlying modelContext is updated. // The basic schema @Model final class Item { var name = "Untitled Item" var folder: Folder? = nil var tags: [Tag] = [] } @Model final class Folder { var name = "Untitled Folder" var items: [Item] = [] } @Model final class Tag { var name = "Untitled Tag" var items: [Item] = [] } // A SwiftUI view to show a Folder. struct FolderRowView: View { let folder: Folder // Should I use an @Query here?? // @Query var items: [Item] var body: some View { HStack { Text(folder.name) Spacer() Text(folder.items.count.formatted()) } } } The above code works, once, but if I then add a new Item to that Folder, then this SwiftUI view does not update. I can make it work if I use an @Query with an #Predicate but even then I'm not quite sure how the #Predicate is supposed to be written. (And it seems excessive to have an @Query on every single row, given how many there could be.) struct FolderView: View { @Query private var items: [Item] private var folder: Folder init(folder: Folder) { self.folder = folder // I've read online that this needs to be captured outside the Predicate? let identifier = folder.persistentModelID _items = Query(filter: #Predicate { link in // Is this syntax correct? The results seem inconsistent in my app... if let folder = link.folder { return folder.persistentModelID == identifier } else { return false } }) } var body: some View { HStack { Text(folder.name) Spacer() // This mostly works. Text(links.count.formatted()) } } } As I try to integrate SwiftData and SwiftUI into a traditional macOS app with a sidebar, content view and inspector I'm finding it challenging to understand how to wire everything up. In this particular example, tracking the count, is there a "correct" way to handle this?
1
0
105
1w
How can I connect NSTableCellView.textField to a SwiftUI view?
When using NSTableView or NSOutlineView, if you use an NSTableCellView and wire up the .imageView and .textField properties then you get some "free" behaviour with respect to styling and sizing of those fields. (ex: They reflect the user's preferred "Sidebar Icon Size" as selected in Settings. ) If I'm using a SwiftUI View inside an NSTableCellView, is there any way to connect a Text or Image to those properties? Consider the following pseudo code: struct MyCellView: View { let text: String let url: URL? var body: some View { HStack { Image(...) // How to indicate this is .imageView? Text(...) // How to indicate this is .textField? } } } final class MyTableCellView: NSTableCellView { private var hostingView: NSHostingView<MyCellView>! init() { self.hostingView = NSHostingView(rootView: MyCellView(text: "", url: nil)) self.addSubview(self.hostingView) } func configureWith(text: String, url: URL) { let rootView = MyCellView(text: text, url: url) hostingView.rootView = rootView // How can I make this connection? self.textField = rootView.??? self.imageView = rootView.??? } } I'm ideally looking for a solution that works on macOS 15+.
2
0
83
2w
On macOS, how do you place a toolbar item on the trailing edge of the window's toolbar when an Inspector view is open?
Using SwiftUI on macOS, how can I add a toolbar item on the right-most (trailing) edge of the window's toolbar when an Inspector is used? At the moment, the toolbar items are all left-of (leading) the split view tracking separator. I want the inspector toolbar item to be placed similar to where Xcode's Inspector toolbar item is placed: always as far right (trailing) as possible. NavigationSplitView { // ... snip } detail: { // ... snip } .inspector(isPresented: $isInspectorPresented) { InspectorContentView() } .toolbar { // What is the correct placement value here? ToolbarItem(placement: .primaryAction) { Button { isInspectorPresented.toggle() } label: { Label("Toggle Inspector", systemImage: "sidebar.trailing") } } } See the attached screenshot. When the InspectorView is toggled open, the toolbar item tracks leading the split view tracking separator, which is not consistent with how Xcode works.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
4
0
69
Aug ’25
How to effectively use task(id:) when multiple properties are involved?
While adopting SwiftUI (and Swift Concurrency) into a macOS/AppKit application, I'm making extensive use of the .task(id:) view modifier. In general, this is working better than expected however I'm curious if there are design patterns I can better leverage when the number of properties that need to be "monitored" grows. Consider the following pseudo-view whereby I want to call updateFilters whenever one of three separate strings is changed. struct FiltersView: View { @State var argument1: String @State var argument2: String @State var argument3: String var body: some View { TextField($argument1) TextField($argument2) TextField($argument3) }.task(id: argument1) { await updateFilters() }.task(id: argument2) { await updateFilters() }.task(id: argument3) { await updateFilters() } } Is there a better way to handle this? The best I've come up with is to nest the properties inside struct. While that works, I now find myself creating these "dummy types" in a bunch of views whenever two or more properties need to trigger an update. ex: struct FiltersView: View { struct Components: Equatable { var argument1: String var argument2: String var argument3: String } @State var components: Components var body: some View { // TextField's with bindings to $components... }.task(id: components) { await updateFilters() } } Curious if there are any cleaner ways to accomplish this because this gets a bit annoying over a lot of views and gets cumbersome when some values are passed down to child views. It also adds an entire layer of indirection who's only purpose is to trigger task(id:).
2
0
74
May ’25
How to hide the tab bar in SwiftUI's TabView for macOS?
In SwiftUI for macOS, how can I hide the tab bar when using TabView? I would like to provide my own tab bar implementation. In AppKit's NSTabViewController, we can do the following: let tabViewController = NSTabViewController() tabViewController.tabStyle = .unspecified I've come across various posts that suggest using the .toolbar modifier, but none appear to work on macOS (or at least I haven't found the right implementation). struct ContentView: View { var body: some View { TabView { // ... content } <- which view modifier hides the tab bar? } } Latest macOS, Latest Xcode
3
0
120
May ’25
Can SwiftUI TextFields in a List on macOS be marked as always editable?
In SwiftUI's List, on macOS, if I embed a TextField then the text field is presented as non-editable. If the user clicks on the text and waits a short period of time, the text field will become editable. I'm aware this is generally the correct behaviour for macOS. However, is there a way in SwiftUI to supress this behaviour such that the TextField is always presented as being editable? I want a scrollable, List of editable text fields, much like how a Form is presented. The reason I'm not using a Form is because I want List's support for reordering by drag-and-drop (.onMove). Use Case A view that allows a user to compose a questionnaire. They are able to add and remove questions (rows) and each question is editable. They require drag-and-drop support so that they can reorder the questions.
0
0
96
May ’25
How do you restore a Sheet's window frame in SwiftUI for macOS
On macOS, it's not uncommon to present windows as sheets that can be resized. By setting the NSWindow's various frame auto save properties, you can restore the size of the sheet the next time it is presented. When presenting a Sheet from within SwiftUI using the .sheet view modifier, how can I preserve and restore the sheet's frame size? The closest I've been able to come is to put the SwiftUI view into a custom NSHostingController and then into an NSViewControllerRepresentable and then override viewWillAppear and look for self.view.window, which is all little awkward. Is there a more idiomatic way to achieve this in "pure" SwiftUI?
2
0
69
May ’25
How to correctly set a Picker's selection and contents in SwiftUI for macOS?
How do you atomically set a Picker's selection and contents on macOS such that you don't end up in a situation where the selection is not present within the Picker's content? I presume Picker on macOS is implemented as an NSPopUpButton and an NSPopUpButton doesn't really like the concept of "no selection". SwiftUI, when presented with that, outputs: Picker: the selection "nil" is invalid and does not have an associated tag, this will give undefined results. Consider the following pseudo code: struct ParentView: View { @State private var items: [Item] var body: some View { ChildView(items: items) } } struct ChildView: View { let items: [Item] @State private var selectedItem: Item? var body: some View { Picker("", selection: $selectedItem) { ForEach(items) { item in Text(item.name).tag(item) } } } } When items gets passed down from ParentView to the ChildView, it's entirely possible that the current value in selectedItem represents an Item that is not longer in the items[] array. You can "catch" that by using .onAppear, .task, .onChange and maybe some other modifiers, but not until after at least one render pass has happened and an error has likely been reported because selectedItem is nil or it's not represented in the items[] array. Because selectedItem is private state, a value can't easily be passed down from the parent view, though even if it could that just kind of moves the problem one level higher up. What is the correct way to handle this type of data flow in SwiftUI for macOS?
1
0
120
May ’25
Is it reasonable to vend an NSView from a "ViewModel" when using NSViewRepresentable instead of implementing the Coordinator pattern?
I'm currently integrating SwiftUI into an AppKit based application and was curious if the design pattern below was viable or not. In order to "bridge" between AppKit and SwiftUI, most of my SwiftUI "root" views have aViewModel that is accessible to the SwiftUI view via @ObservedObject. When a SwiftUI views need to use NSViewRepresentable I'm finding the use of a ViewModel and a Coordinator to be an unnecessary layer of indirection. In cases where it makes sense, I've just used the ViewModel as the Coordinator and it all appears to be working ok, but I'm curious if this is reasonable design pattern or if I'm overlooking something. Consider the following pseudo code: // 1. A normal @ObservedObject acting as the ViewModel that also owns and manages an NSTableView. @MainActor final class ViewModel: ObservedObject, NSTableView... { let scrollView: NSScrollView let tableView: NSTableView @Published var selectedTitle: String init() { // ViewModel manages tableView as its dataSource and delegate. tableView.dataSource = self tableView.delegate = self } func reload() { tableView.reloadData() } // Update view model properties. // Simpler than passing back up through a Coordinator. func tableViewSelectionDidChange(_ notification: Notification) { selectedTitle = tableView.selectedItem.title } } // 2. A normal SwiftUI view, mostly driven by the ViewModel. struct ContentView: View { @ObservedObject model: ViewModel var body: some View { Text(model.selectedTitle) // No need to pass anything down other than the view model. MyTableView(model: model) Button("Reload") { model.reload() } Button("Delete") { model.deleteRow(...) } } } // 3. A barebones NSViewRepresentable that just vends the required NSView. No other state is required as the ViewModel handles all interactions with the view. struct MyTableView: NSViewRepresentable { // Can this even be an NSView? let model: ViewModel func makeNSView(context: Context) -> some NSView { return model.scrollView } func updateNSView(_ nsView: NSViewType, context: Context) { // Not needed, all updates are driven through the ViewModel. } } From what I can tell, the above is working as expected, but I'm curious if there are some situations where this could "break", particularly around the lifecycle of NSViewRepresentable Would love to know if overall pattern is "ok" from a SwiftUI perspective.
0
0
46
Apr ’25
The @Environment(\.dismiss) value in SwiftUI for macOS does not dismiss a sheet presented by an NSWindowController.
I'm wondering what the correct, or recommended, way is to dismiss a SwiftUI that is being presented as a sheet hosted by an NSHostingController. The usual technique of invoking @Environment(\.dismiss) does not appear to work. Consider the code below. An NSWindowController is attempting to display a SwiftUI SettingsView as a sheet. The sheet is correctly presented, but the SettingsView is unable to dismiss itself. I am able to make it work by passing a closure into SettingsView that calls back to the NSWindowController but it's rather convoluted because SettingsView doesn't know the view controller that's hosting it until after SettingsView has been created, which means "finding" that view controller in the window controller to dismiss is more involved than it should be. Is there a better strategy to leverage here? final class MyViewController: NSViewController { @IBAction func buttonClicked(_ sender: NSButton) { if let presenter = window?.contentViewController { presenter.presentAsSheet(NSHostingController(rootView: SettingsView())) } } } struct SettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { VStack { Button("Cancel", role: .cancel) { dismiss() // This call does not dismiss the sheet. } .keyboardShortcut(.cancelAction) } } } Thank you. macOS 15.4.1 (24E263), Xcode 16.3 (16E140)
0
0
49
Apr ’25