Mac上的DatePicker在按下返回键之前不会保存日期
Posted
技术标签:
【中文标题】Mac上的DatePicker在按下返回键之前不会保存日期【英文标题】:DatePicker on Mac not saving date until return key is pressed 【发布时间】:2020-08-10 10:18:36 【问题描述】:我正在使用 Mac Catalyst 将我的 iPad 应用程序调整到 Mac,但 datePicker 出现问题(它的时间为 datePickerMode
)。在 iPad 上,datePicker 是一个***,只要用户在日期选择器上滚动,就会触发 dateChanged 操作。但在 Mac 上,日期选择器不是滚动条,而是一种文本输入。我可以在 Mac 上键入和更改所有时间值,但是在按下返回键之前不会触发 dateChanged 操作。
我想在用户输入某个时间时触发 dateChange 操作。我该怎么做?我尝试向 datePicker 添加不同的目标,但没有任何效果。
我实际上更喜欢在 Mac 上使用日期滚动器,所以如果有人知道如何执行此操作,我将不胜感激(我在互联网上到处寻找,但一无所获)!
这是我的代码:
class DateVC: UIViewController
@IBOutlet weak var datePicker: UIDatePicker!
override func viewDidLoad()
super.viewDidLoad()
//Just show the time
datePicker.datePickerMode = .time
//Action connected to datePicker. This is not called until I press enter on Mac
@IBAction func datePickerChanged(_ sender: Any)
//do actions
【问题讨论】:
我没有适用于 Mac 的日期滚动条,但我有一个不错的 SwiftUI 时钟,带有时针和分针,您可以在 ios 和 maccatalyst 中使用。它可能很有趣。库位于:github.com/workingDog/ClockTimePicker 使用示例:github.com/workingDog/ClockPicker 这听起来像是 Mac Catalyst 中的一个错误。我有一个带有 NSDatePicker 的 mac 应用程序,即使用户使用键盘输入日期,该操作也会始终触发。 我遇到了同样的错误并通过 Xcode 提交了错误报告。 Apple 已跟进请求更多信息,因此我制作了一个示例项目供他们运行,因此希望这将很快得到解决。非常令人沮丧。 【参考方案1】:这是一个 SwiftUI 解决方案,可在 iPad、iPhone 和 Mac Catalyst 上显示日期和时间滚动选择器。无需按返回键即可工作。如果需要,您可以轻松地仅显示 HoursMinutesPicker。
import SwiftUI
struct ContentView: View
@State var date = Date()
var body: some View
NavigationView
NavigationLink(destination: DateHMPicker(date: self.$date))
VStack
Text("Show time")
Text("\(self.date)")
.navigationViewStyle(StackNavigationViewStyle())
struct DateHMPicker: View
var titleKey: LocalizedStringKey = ""
@Binding var date: Date
var body: some View
HStack
Spacer()
DatePicker(titleKey, selection: self.$date, displayedComponents: .date).datePickerStyle(WheelDatePickerStyle())
HoursMinutesPicker(date: self.$date)
Spacer()
struct HoursMinutesPicker: View
@Binding var date: Date
@State var hours: Int = 0
@State var minutes: Int = 0
var body: some View
HStack
Spacer()
Picker("", selection: Binding<Int>(
get: self.hours,
set :
self.hours = $0
self.update()
))
ForEach(0..<24, id: \.self) i in
Text("\(i) hours").tag(i)
.pickerStyle(WheelPickerStyle()).frame(width: 90).clipped()
Picker("", selection: Binding<Int>(
get: self.minutes,
set :
self.minutes = $0
self.update()
))
ForEach(0..<60, id: \.self) i in
Text("\(i) min").tag(i)
.pickerStyle(WheelPickerStyle()).frame(width: 90).clipped()
Spacer()
.onAppear(perform: loadData)
func loadData()
self.hours = Calendar.current.component(.hour, from: date)
self.minutes = Calendar.current.component(.minute, from: date)
func update()
if let newDate = Calendar.current.date(bySettingHour: self.hours, minute: self.minutes, second: 0, of: date)
date = newDate
【讨论】:
谢谢,但我不想拥有 WheelPickerStyle。 Mac 催化剂上的 UIDatePicker 的优点是它是一种文本字段格式,因此它允许用户使用键盘输入日期/时间 对不起,我看错了你的问题。我认为“我实际上更喜欢在 Mac 上使用日期滚动条”意味着您想要 WheelPickerStyle。您是否正在寻找仅用于时间的文本字段类型? 对不起,原来的问题不是我的,所以我看到你的困惑。我希望将它用于日期和时间。在 Mac 催化剂中,它为日期的文本字段提供了一个不错的日历【参考方案2】:如何将 DatePicker 用于日期部分,将以下文本字段用于时间输入部分。
import SwiftUI
import Combine
struct ContentView: View
@State var date = Date()
var body: some View
NavigationView
NavigationLink(destination: DateHMPicker(date: self.$date))
VStack
Text("Show time")
Text("\(self.date)")
.navigationViewStyle(StackNavigationViewStyle())
struct DateHMPicker: View
@State var labelText = ""
@Binding var date: Date
var body: some View
HStack
Spacer()
DatePicker(labelText, selection: self.$date, displayedComponents: .date)
Spacer()
HoursMinutesPicker(date: self.$date).frame(width: 90)
.fixedSize()
struct TextFieldTime: View
let range: ClosedRange<Int>
@Binding var value: Int
var handler: () -> Void
@State private var isGood = false
@State private var textValue = ""
@State private var digits = 2
var body: some View
TextField("", text: $textValue)
.font(Font.body.monospacedDigit())
.onReceive(Just(textValue)) txt in
// must be numbers
var newTxt = txt.filter "0123456789".contains($0)
if newTxt == txt
// restrict the digits
if newTxt.count > self.digits
newTxt = String(newTxt.dropLast())
// check the number
self.isGood = false
if let number = NumberFormatter().number(from: newTxt)
if self.range.contains(number.intValue)
self.textValue = newTxt
self.value = number.intValue
self.isGood = true
else
self.textValue = self.textValue.count == 1
? String(self.range.lowerBound) : String(self.textValue.dropLast())
if self.value >= 0 && self.isGood
self.handler()
else
self.textValue = newTxt.isEmpty ? String(self.range.lowerBound) : newTxt
.onAppear(perform:
self.textValue = String(self.value)
self.digits = String(self.range.upperBound).count
)
.fixedSize()
struct HoursMinutesPicker: View
@Binding var date: Date
@State var separator = ":"
@State var hours: Int = 0
@State var minutes: Int = 0
var body: some View
HStack (spacing: 1)
TextFieldTime(range: 0...23, value: self.$hours, handler: self.update)
Text(separator)
TextFieldTime(range: 0...59, value: self.$minutes, handler: self.update)
.onAppear(perform: loadData).padding(5)
func loadData()
self.hours = Calendar.current.component(.hour, from: date)
self.minutes = Calendar.current.component(.minute, from: date)
func update()
let baseDate = Calendar.current.dateComponents([.year, .month, .day], from: date)
var dc = DateComponents()
dc.year = baseDate.year
dc.month = baseDate.month
dc.day = baseDate.day
dc.hour = self.hours
dc.minute = self.minutes
if let newDate = Calendar.current.date(from: dc), date != newDate
date = newDate
【讨论】:
这个答案是否提供了一种解决方法,不需要用户在调整时间后按回车键?【参考方案3】:因为您的函数与 @IBAction 相关联,该函数将在操作时调用,例如“按钮按下”
你应该遵循不同的方法。
let datePicker = UIDatePicker()
datePicker.datePickerMode = .date
dateTextField.inputView = datePicker
datePicker.addTarget(self, action: #selector(datePickerChanged(picker:)), for: .valueChanged)
这是你的功能:
@objc func datePickerChanged(picker: UIDatePicker)
//do your action here
【讨论】:
这不会在 MacCatalyst 上触发而不按回车键【参考方案4】:我没有找到使用内置 UIDatePicker 的解决方案。我最终转而使用JBCalendarDatePicker,它实现了相同的外观/感觉。
【讨论】:
【参考方案5】:如果您更喜欢 Mac Catalyst 中 DatePicker 的滚轮格式,请将您的 Date Picker 样式更改为 Wheels。它将在 Mac 上正确显示。
我将我的 iPhone/iPad 应用程序转换为在 Mac Catalyst 上运行。我在 MacOS Catalina 10.15.5 上使用 Xcode 11.4.1。我在应用程序的 Mac 版本上将 DatePicker 显示为***时遇到问题。在 Mac 模拟器上,它显示为文本字段,但单击日期字段之一时会显示日历。我觉得继续使用滚轮显示会带来更好的用户体验。
一个非常简单的解决方法是在 Storyboard 中选择 DatePicker。显示属性检查器。将您的样式从“自动”更改为“***”,在 Mac Catalyst 版本上,显示将返回显示为***。
【讨论】:
我还发现您应该检查属性检查器下的模式设置,以查看日期和时间、日期或时间,以便***显示正确的值。【参考方案6】:大约 1 周前,我向 Apple 提交了错误报告。 现在我执行以下操作来强制日期选择器使用轮格式。这会在***旋转时触发 onchangedlistener。
if #available(macCatalyst 13.4, *)
datePickerView.preferredDatePickerStyle = .wheels
【讨论】:
以上是关于Mac上的DatePicker在按下返回键之前不会保存日期的主要内容,如果未能解决你的问题,请参考以下文章
为啥鼠标右键单击在按下时会触发“pointerdown”事件,但在释放时不会触发“pointerup”事件?