如何让按钮(或任何其他元素)在点击时显示 SwiftUI 的 DatePicker 弹出窗口?

Mik*_*oon 3 ios swift swiftui

我正在尝试实现最简单的用例,但我无法弄清楚。我有一张日历图片。我想要的只是在点击图片时显示 DatePicker 弹出窗口。我试图将它放在 ZStack 中,但这样做我无法隐藏默认数据文本字段:

ZStack {
    Image("icon-calendar")
    .zIndex(1)
    DatePicker("", selection: $date)
    .zIndex(2)
}
Run Code Online (Sandbox Code Playgroud)

如何在没有荒谬的解决方法的情况下本地制作这种简单的布局?

Csl*_*lim 22

对于那些仍在寻找简单解决方案的人,我一直在寻找类似的解决方案,并在YouTube 上的 Kavasoft 教程(视频 20:32)中找到了一个很好的示例,说明如何执行此操作。

这是他使用的:

import SwiftUI

struct DatePickerView: View {

    @State private var birthday = Date()
    @State private var isChild = false
    @State private var ageFilter = ""

    var body: some View {

        Image(systemName: "calendar")
          .font(.title3)
          .overlay{ //MARK: Place the DatePicker in the overlay extension
             DatePicker(
                 "",
                 selection: $birthday,
                 displayedComponents: [.date]
             )
              .blendMode(.destinationOver) //MARK: use this extension to keep the clickable functionality
              .onChange(of: birthday, perform: { value in
                  isChild = checkAge(date:birthday)
               })
          }
    }

    //MARK: I added this function to show onChange functionality remains the same

    func checkAge(date: Date) -> Bool  {
        let today = Date()
        let diffs = Calendar.current.dateComponents([.year], from: date, to: today)
        let formatter = DateComponentsFormatter()
        let outputString = formatter.string(from: diffs)
        self.ageFilter = outputString!.filter("0123456789.".contains)
        let ageTest = Int(self.ageFilter) ?? 0
        if ageTest > 18 {
            return false
        }else{
            return true
        }
    }
}

    

 
Run Code Online (Sandbox Code Playgroud)

关键是将 DatePicker 放在 Image 下方的覆盖层中。完成后,需要将 .blendmode 扩展名设置为 .desintationOver 才能单击。我添加了一个简单的检查年龄函数,以显示 onChange 功能在以这种方式使用时保持不变。

我在 Xcode 14(SwiftUI 4.0 和 IOS 16)中测试了这段代码。

我希望这对其他人有帮助!

演示

演示图像日期选择器


小智 6

尝试在导航栏项目中使用 Hieu 的解决方案,但它失败了。通过直接使用我想要显示的组件上的 和 对其进行修改,它的工作方式就像一个魅力SwiftUIWrapperallowsHitTesting

也适用于列表和表单

struct StealthDatePicker: View {
    @State private var date = Date()
    var body: some View {
        ZStack {
            DatePicker("", selection: $date, in: ...Date(), displayedComponents: .date)
                .datePickerStyle(.compact)
                .labelsHidden()
            SwiftUIWrapper {
                Image(systemName: "calendar")
                .resizable()
                .frame(width: 32, height: 32, alignment: .topLeading)
            }.allowsHitTesting(false)
        }
    }
}

struct SwiftUIWrapper<T: View>: UIViewControllerRepresentable {
    let content: () -> T
    func makeUIViewController(context: Context) -> UIHostingController<T> {
        UIHostingController(rootView: content())
    }
    func updateUIViewController(_ uiViewController: UIHostingController<T>, context: Context) {}
}
Run Code Online (Sandbox Code Playgroud)


Đin*_*iếu 5

我也有这个问题。想着解决办法,我几天睡不着觉。我已经用谷歌搜索了数百次,最后,我找到了实现这一目标的方法。现在是我所在时区的凌晨 1:50,我现在可以愉快地睡觉了。信用在这里追逐的答案

演示在这里:https : //media.giphy.com/media/2ILs7PZbdriaTsxU0s/giphy.gif

神奇的代码

struct ContentView: View {
    @State var date = Date()
    
    var body: some View {
        ZStack {
            DatePicker("label", selection: $date, displayedComponents: [.date])
                .datePickerStyle(CompactDatePickerStyle())
                .labelsHidden()
            Image(systemName: "calendar")
                .resizable()
                .frame(width: 32, height: 32, alignment: .center)
                .userInteractionDisabled()
        }
    }
}

struct NoHitTesting: ViewModifier {
    func body(content: Content) -> some View {
        SwiftUIWrapper { content }.allowsHitTesting(false)
    }
}

extension View {
    func userInteractionDisabled() -> some View {
        self.modifier(NoHitTesting())
    }
}

struct SwiftUIWrapper<T: View>: UIViewControllerRepresentable {
    let content: () -> T
    func makeUIViewController(context: Context) -> UIHostingController<T> {
        UIHostingController(rootView: content())
    }
    func updateUIViewController(_ uiViewController: UIHostingController<T>, context: Context) {}
}
Run Code Online (Sandbox Code Playgroud)


lor*_*sum 2

struct ZCalendar: View {
    @State var date = Date()
    @State var isPickerVisible = false
    var body: some View {
        ZStack {
            Button(action: {
                isPickerVisible = true
            }, label: {
                Image(systemName: "calendar")
            }).zIndex(1)
            if isPickerVisible{
                VStack{
                    Button("Done", action: {
                        isPickerVisible = false
                    }).padding()
                    DatePicker("", selection: $date).datePickerStyle(GraphicalDatePickerStyle())
                }.background(Color(UIColor.secondarySystemBackground))
                .zIndex(2)
            }
        }//Another way
        //.sheet(isPresented: $isPickerVisible, content: {DatePicker("", selection: $date).datePickerStyle(GraphicalDatePickerStyle())})
    }
}
Run Code Online (Sandbox Code Playgroud)