In my SwiftUI app on macOS Sonoma I am using several Picker
views. Here is one example:
Picker("Berichtsart", selection: $report.reportType) {
ForEach(ReportType.allCases) { option in
Image(systemName: option.iconString)
.help(option.description)
}
}
.fixedSize()
.pickerStyle(.segmented)
.labelsHidden()
.onChange(of: report.reportType) {
// Do something here when the user changes the selection thru the picker
reports.push(report)
}
The onChange
closure get executed every time report.reportType
changes. It runs when the user clicks on a different segment of the Picker
, but it also runs if some other code changes the value of the Binding
.
But I am looking for a way to run the code in the onChange
only when the user triggers the change through the picker, and not, when some other code changes report
.
TLDR: I want to run some code when a user actively changes the selection on a Picker
, but not if something else changes the Binding
the picker uses to store its selection.
Any hints and pointers are greatly appreciated. Thanks!
You can make a simple interceptor and use it where you intended (like the picker selection) instead of directly passing the source like:
var pickerSelectionInterceptor = Binding<ReportType>(
get: { report.reportType },
set: {
report.reportType = $0
print("Changed \(report.reportType)") // 👈 Do your stuff here
}
)
Picker("Berichtsart", selection: pickerSelectionInterceptor) { ... }
/* .onChange(of: report.reportType) { ... } */ // 👈 No need to observe the source changes for this specific reason.