SwiftUI DatePicker 在更改日期时在短日期和中日期格式之间跳转

问题描述 投票:0回答:3

(使用 Xcode 12.3 和 iOS 14.3)

我使用默认样式 (

DatePicker
) 的
DefaultDatePickerStyle
组件来显示和编辑日期:该组件在标签中显示当前日期值,并在点击该标签时弹出日历。到目前为止,一切都很好。

当我更改日期(以编程方式或在 UI 中手动更改)时,组件会不规律地更改其标签的日期格式。它似乎在

.short
.medium
DateFormatter.Style
值之间切换。请注意,日期格式不能以编程方式设置,它是
DatePicker
.

的内部格式

举个例子:

DatePicker
显示“2021年2月7日”;我通过使用按钮减去一天来更改日期,导致组件显示“2/6/21”;再次减去一天,显示变为“2021 年 2 月 5 日”等。有时它会在几个日期保持相同的格式,但大多数情况下它会在每次更改时切换。

示例代码:

struct DateView: View {
  @State var date = Date()

  var body: some View {
    VStack(spacing: 20) {
      Button("-1 day") {
        date.addTimeInterval(-24*60*60)
      }
      Button("+1 day") {
        date.addTimeInterval(24*60*60)
      }
      DatePicker(
        "Date",
        selection: $date,
        displayedComponents: .date
      ).labelsHidden()
    }
  }
}

省略

displayedComponents
labelsHidden
对问题没有影响。

重复打开日历弹窗和选择日期时会出现同样的问题:关闭弹窗后,显示的日期有时是短格式,有时是中格式。

知道那里发生了什么吗?

ios swiftui
3个回答
36
投票

看起来像一个错误。这是找到的解决方法(使用 Xcode 13beta / iOS 15 测试)

  DatePicker(
    "Date",
    selection: $date,
    displayedComponents: .date
  )
  .labelsHidden()
  .id(date)             // << here !!

2
投票

对我来说,建议的解决方法确实有效,但在以正确的方式格式化之前,日期仍会在很短的时间内显示短格式。另一种对我来说没有任何问题的方法是包装一个

UIDatePicker
以在SwiftUI中使用它而不是使用视图中的构建(取自https://stackoverflow.com/a/59853272/13440564)。

struct MyDatePicker: UIViewRepresentable {
    @Binding var date: Date
    var range: ClosedRange<Date>

    func makeUIView(context: Context) -> UIDatePicker {
        let datePicker = UIDatePicker()
        datePicker.datePickerMode = .date
        datePicker.addTarget(context.coordinator, action: #selector(Coordinator.changed(_:)), for: .valueChanged)
        datePicker.minimumDate = range.lowerBound
        datePicker.maximumDate = range.upperBound
        return datePicker
    }

    func updateUIView(_ datePicker: UIDatePicker, context: Context) {
        datePicker.date = date
    }

    func makeCoordinator() -> MyDatePicker.Coordinator {
        Coordinator(date: $date)
    }

    class Coordinator: NSObject {
        private let date: Binding<Date>

        init(date: Binding<Date>) {
            self.date = date
        }

        @objc func changed(_ sender: UIDatePicker) {
            self.date.wrappedValue = sender.date
        }
    }
}

您可以像这样简单地调用它并根据您的需要对其进行自定义:

HStack {
    Text("Select date")

    Spacer()

    MyDatePicker(
        date: $date,
        range: range
    ).frame(maxHeight: 35)
}

0
投票

我正在尝试将

DatePicker
绑定到核心数据
NSManagedObject
上的日期,并且我正在显示这样的日历弹出窗口:

另一个 SwiftUI 解决方案(推荐

.id(date)
)对我不起作用,而是弹出窗口表现得很奇怪,每次点击都会消失。

我所做的是将日期放入状态变量中:

    @State private var snoozeUntilDate = Date()

每当显示日期选择器时,将此变量初始化为托管对象的日期:

DatePicker("Snooze until date", selection: $snoozeUntilDate, displayedComponents: .date)
    .labelsHidden()
    .onAppear {
        snoozeUntilDate = task.snoozeUntilDate!
    }

每当

@State
变量改变时更新管理对象:

    .onChange(of: snoozeUntilDate) { newDate in
        task.snoozeUntilDate = newDate
    }

这样做已经解决了我的问题! 🥳

虽然我不是百分百确定,但我认为这里的问题可能是由托管对象引起的。我尝试使

@State
变量成为可选的 (
Date?
),但这并没有重新引入怪异,因此似乎绑定到托管对象(我使用
Binding(task.snoozeUntilDate)!
创建)可能是奇怪的来源。

© www.soinside.com 2019 - 2024. All rights reserved.