SwiftUI:带有自定义设计的紧凑日期选择器。

4
我需要一个自定义的“标签”,具有在某种弹出窗口中打开日期选择器的行为,即使在iPhone上也是如此。
当我使用紧凑格式的内置DatePicker时,我有打开弹出窗口中的滚轮的行为,但我无法自定义“折叠”版本的外观,其中包括灰色背景(实际上,我可以将其更改为其他颜色,但不能更改为白色,例如,它根本不起作用)。
另一种选择是在Button中包装自定义Text,然后打开DatePicker,但我不知道如何在iPhone上实现弹出窗口效果。因此,我想第一种选择会更容易一些,但我如何实现紧凑日期选择器的自定义布局?没有超级花哨的东西,就像这样:

enter image description here

代替这样的东西

enter image description here

2个回答

5

这更多是一个概念验证,但这可能是一种方式:


import SwiftUI

struct ContentView: View {
    @State private var showPicker = true
    @State var selectedDate = Date()

        Button {
            withAnimation {
                showPicker.toggle()
            }
        }  label: {
            Text(Text(selectedDate.getFormattedDate(format:"HH:mm:")))
                .padding()
                .padding(.horizontal)
                .background(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(Color.gray)
                )
        }
        .background(
            DatePicker("", selection: $selectedDate, displayedComponents: .hourAndMinute)
                .datePickerStyle(.wheel)
                .frame(width: 200, height: 100)
                .clipped()
                .background(Color.gray.cornerRadius(10))
                .opacity(showPicker ? 1 : 0 )
                .offset(x: 50, y: 90)
               ).onChange(of: selectedDate) { newValue in
                   
                   withAnimation {
                       showPicker.toggle()
                   }
               }
}

请注意,对于对象来说,无法使用DidSet或willSet,但是我们有一个不错的解决方法onChange。当日期发生变化时,只需切换即可完成。

这已经是一个很大的进步了,非常感谢!我需要再调整一下zindex,但似乎已经有一个可行的解决方案了。唯一不太好的地方是用户必须再次点击按钮才能隐藏DatePicker;你看到任何可能让他们点击任何地方来隐藏它的可能性吗? - swalkner
不幸的是,在SwiftUI中,取消任何地方的点击操作是一个相当复杂的问题...你可以在所有内容后面放置一个“几乎”透明的视图(不透明度为0.01),并检测该视图上的点击。 - ChrisR
另一种方法是将UIKit的UIDatePicker包装到UIViewRepresentable中并更改其标签。但我不是一个UIKit专家 :) - ChrisR
你可以通过叠加层来添加一个完成按钮以关闭选择器。我已经这样做了。 - Tanvirgeek
不要使用.onChange(),这样会很烦人,而是使用.onTapGesture(),这样你仍然可以滑动选择器,但在点击时会隐藏选择器。 - undefined
显示剩余2条评论

2
这个方法有点取巧,但另一种方法是将实际的DatePicker视图的不透明度设置为0.011(这是我找到的最小不透明度值,可以很好地隐藏它并保持其功能),然后使用.overlay将其放在你定制的视图上面,下面是一个示例:
struct MyDatePicker: View {
    @State private var selectedDate = Date()

    var body: some View {
        
        // Put your own design here
        HStack(spacing: 2) {
            Text(selectedDate.formatted(.dateTime.day().month().year()))
                .font(.system(size: 13, weight: .semibold))
        
            Image(systemName: "chevron.right")
                .font(.system(size: 9, weight: .bold))
        }
        .padding(8)
        .foregroundColor(.white)
        .background(RoundedRectangle(cornerRadius: 15, style: .continuous).foregroundColor(.blue))

        // Put the actual DataPicker here with overlay
        .overlay {
            DatePicker(selection: $selectedDate, displayedComponents: .date) {}
                .labelsHidden()
                .contentShape(Rectangle())
                .opacity(0.011)             // <<< here
        }

    }
}

这是结果: {{link1:输入图像描述}}

非常好的解决方案,谢谢。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接