As Image below shows, if you type the date "Jan 11 2023", it presents the date picker. What I wanna to achieve is have a button elsewhere, when that button is clicked, present this date picker automatically.
Does anyone know if there is a way to achieve it?
DatePicker("Jump to", selection: $date, in: dateRange, displayedComponents: [.date])
Below is a test on @rob mayoff's answer. I still couldn't figure out why it didn't work yet.
I tested on Xcode 14.2 with iPhone 14 with iOS 16.2 simulator, as well as on device. What I noticed is that although the triggerDatePickerPopover()
is called, it never be able to reach button.accessibilityActivate()
.
import SwiftUI
struct ContentView: View {
@State var date: Date = .now
let dateRange: ClosedRange<Date> = Date(timeIntervalSinceNow: -864000) ... Date(timeIntervalSinceNow: 864000)
var pickerId: String { "picker" }
var body: some View {
VStack {
DatePicker(
"Jump to",
selection: $date,
in: dateRange,
displayedComponents: [.date]
)
.accessibilityIdentifier(pickerId)
Button("Clicky") {
triggerDatePickerPopover()
print("Clicky Triggered")
}
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension NSObject {
func accessibilityDescendant(passing test: (Any) -> Bool) -> Any? {
if test(self) { return self }
for child in accessibilityElements ?? [] {
if test(child) { return child }
if let child = child as? NSObject, let answer = child.accessibilityDescendant(passing: test) {
return answer
}
}
for subview in (self as? UIView)?.subviews ?? [] {
if test(subview) { return subview }
if let answer = subview.accessibilityDescendant(passing: test) {
return answer
}
}
return nil
}
}
extension NSObject {
func accessibilityDescendant(identifiedAs id: String) -> Any? {
return accessibilityDescendant {
// For reasons unknown, I cannot cast a UIView to a UIAccessibilityIdentification at runtime.
return ($0 as? UIView)?.accessibilityIdentifier == id
|| ($0 as? UIAccessibilityIdentification)?.accessibilityIdentifier == id
}
}
func buttonAccessibilityDescendant() -> Any? {
return accessibilityDescendant { ($0 as? NSObject)?.accessibilityTraits == .button }
}
}
extension ContentView {
func triggerDatePickerPopover() {
if
let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = scene.windows.first,
let picker = window.accessibilityDescendant(identifiedAs: pickerId) as? NSObject,
let button = picker.buttonAccessibilityDescendant() as? NSObject
{
print("triggerDatePickerPopover")
button.accessibilityActivate()
}
}
}
Update 2: I followed up the debug instruction. It seems that with exact same code. My inspector are missing the accessibility identifier. Not knowing why.... feels mind buggingly now.
Here is a link to download the project https://www.icloud.com/iclouddrive/040jHC0jwwJg3xgAEvGZShqFg#DatePickerTest
Update 3: @rob mayoff's solution is brilliant! For anyone reading. If it didn't work in your case, just wait. It's probably just due to device or simulator getting ready for accessibility.