如何在 SwiftUI 上的 DatePicker 中设置 countDownTimer 模式?
How can I set countDownTimer mode in DatePicker on SwiftUI?
使用 UIKit,UIDatePicker 允许将模式设置为 UIDatePicker.Mode.countDownTimer,我们可以设置持续时间。
使用 SwiftUI,我看不到任何解决此问题的本地方法。
唯一的方法是与 UIKit 进行交互?
[更新]
仅找到解决方案
DurationPickerView.swift
import SwiftUI
import UIKit
struct DurationPickerView: UIViewRepresentable {
@Binding var time: Time
func makeCoordinator() -> DurationPickerView.Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .countDownTimer
datePicker.addTarget(context.coordinator, action: #selector(Coordinator.onDateChanged), for: .valueChanged)
return datePicker
}
func updateUIView(_ datePicker: UIDatePicker, context: Context) {
let date = Calendar.current.date(bySettingHour: time.hour, minute: time.minute, second: time.second, of: datePicker.date)!
datePicker.setDate(date, animated: true)
}
class Coordinator: NSObject {
var durationPicker: DurationPickerView
init(_ durationPicker: DurationPickerView) {
self.durationPicker = durationPicker
}
@objc func onDateChanged(sender: UIDatePicker) {
print(sender.date)
let calendar = Calendar.current
let date = sender.date
durationPicker.time = Time(hour: calendar.component(.hour, from: date), minute: calendar.component(.minute, from: date), second: calendar.component(.second, from: date))
}
}
}
Time.swift
import Foundation
struct Time {
var hour: Int
var minute: Int
var second: Int = 0
}
现在获得倒计时行为的唯一方法是将 UIDatePicker
包装在自定义视图中。
这是使用 countDownDuration
的 代码的简化版本。
import SwiftUI
struct DurationPicker: UIViewRepresentable {
@Binding var duration: TimeInterval
func makeUIView(context: Context) -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .countDownTimer
datePicker.addTarget(context.coordinator, action: #selector(Coordinator.updateDuration), for: .valueChanged)
return datePicker
}
func updateUIView(_ datePicker: UIDatePicker, context: Context) {
datePicker.countDownDuration = duration
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject {
let parent: DurationPicker
init(_ parent: DurationPicker) {
self.parent = parent
}
@objc func updateDuration(datePicker: UIDatePicker) {
parent.duration = datePicker.countDownDuration
}
}
}
这是另一个解决方案。它只是将两个选择器并排放置,所以看起来不太好。但它确实避免了另一个答案中的错误,即它不会在第一次更新选择器中选择的值。
import SwiftUI
struct CountDownPicker: View {
var hours = Array(0...23)
var min = Array(0...59)
@Binding var selectedHours: Int
@Binding var selectedMins: Int
var body: some View {
GeometryReader { geometry in
HStack {
Picker(selection: $selectedHours, label: Text("hrs")) {
ForEach(0..<self.hours.count) {
Text("\(self.hours[[=10=]]) hrs")
.bold()
}
}
.frame(maxWidth: geometry.size.width / 2)
.clipped()
.pickerStyle(.wheel)
Picker(selection: self.$selectedMins, label: Text("mins")) {
ForEach(0..<self.min.count) {
Text("\(self.min[[=10=]]) mins")
.bold()
}
}
.frame(maxWidth: geometry.size.width / 2)
.clipped()
.pickerStyle(.wheel)
}
}
.offset(y: -100)
.padding()
.frame(width: .infinity, height: 140, alignment: .center)
}
}
使用 UIKit,UIDatePicker 允许将模式设置为 UIDatePicker.Mode.countDownTimer,我们可以设置持续时间。
使用 SwiftUI,我看不到任何解决此问题的本地方法。
唯一的方法是与 UIKit 进行交互?
[更新]
仅找到解决方案
DurationPickerView.swift
import SwiftUI
import UIKit
struct DurationPickerView: UIViewRepresentable {
@Binding var time: Time
func makeCoordinator() -> DurationPickerView.Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .countDownTimer
datePicker.addTarget(context.coordinator, action: #selector(Coordinator.onDateChanged), for: .valueChanged)
return datePicker
}
func updateUIView(_ datePicker: UIDatePicker, context: Context) {
let date = Calendar.current.date(bySettingHour: time.hour, minute: time.minute, second: time.second, of: datePicker.date)!
datePicker.setDate(date, animated: true)
}
class Coordinator: NSObject {
var durationPicker: DurationPickerView
init(_ durationPicker: DurationPickerView) {
self.durationPicker = durationPicker
}
@objc func onDateChanged(sender: UIDatePicker) {
print(sender.date)
let calendar = Calendar.current
let date = sender.date
durationPicker.time = Time(hour: calendar.component(.hour, from: date), minute: calendar.component(.minute, from: date), second: calendar.component(.second, from: date))
}
}
}
Time.swift
import Foundation
struct Time {
var hour: Int
var minute: Int
var second: Int = 0
}
现在获得倒计时行为的唯一方法是将 UIDatePicker
包装在自定义视图中。
这是使用 countDownDuration
的
import SwiftUI
struct DurationPicker: UIViewRepresentable {
@Binding var duration: TimeInterval
func makeUIView(context: Context) -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .countDownTimer
datePicker.addTarget(context.coordinator, action: #selector(Coordinator.updateDuration), for: .valueChanged)
return datePicker
}
func updateUIView(_ datePicker: UIDatePicker, context: Context) {
datePicker.countDownDuration = duration
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject {
let parent: DurationPicker
init(_ parent: DurationPicker) {
self.parent = parent
}
@objc func updateDuration(datePicker: UIDatePicker) {
parent.duration = datePicker.countDownDuration
}
}
}
这是另一个解决方案。它只是将两个选择器并排放置,所以看起来不太好。但它确实避免了另一个答案中的错误,即它不会在第一次更新选择器中选择的值。
import SwiftUI
struct CountDownPicker: View {
var hours = Array(0...23)
var min = Array(0...59)
@Binding var selectedHours: Int
@Binding var selectedMins: Int
var body: some View {
GeometryReader { geometry in
HStack {
Picker(selection: $selectedHours, label: Text("hrs")) {
ForEach(0..<self.hours.count) {
Text("\(self.hours[[=10=]]) hrs")
.bold()
}
}
.frame(maxWidth: geometry.size.width / 2)
.clipped()
.pickerStyle(.wheel)
Picker(selection: self.$selectedMins, label: Text("mins")) {
ForEach(0..<self.min.count) {
Text("\(self.min[[=10=]]) mins")
.bold()
}
}
.frame(maxWidth: geometry.size.width / 2)
.clipped()
.pickerStyle(.wheel)
}
}
.offset(y: -100)
.padding()
.frame(width: .infinity, height: 140, alignment: .center)
}
}