swift - 在 SwiftUI 中处理派生状态
问题描述
说我正在创建一个“日期编辑器”视图。目标是: - 采用默认的种子日期。- 它允许用户更改输入。- 如果用户随后选择,他们可以按“保存”,在这种情况下,视图的所有者可以决定对数据进行处理。
这是实现它的一种方法:
struct AlarmEditor : View {
var seedDate : Date
var handleSave : (Date) -> Void
@State var editingDate : Date?
var body : some View {
let dateBinding : Binding<Date> = Binding(
get: {
return self.editingDate ?? seedDate
},
set: { date in
self.editingDate = date
}
)
return VStack {
DatePicker(
selection: dateBinding,
displayedComponents: .hourAndMinute,
label: { Text("Date") }
)
Spacer()
Button(action: {
self.handleSave(dateBinding.wrappedValue)
}) {
Text("Save").font(.headline).bold()
}
}
}
}
问题
如果所有者更改 的值seedDate
怎么办?
说在那种情况下,我想做的是将值重置为editingDate
新的种子日期。
这样做的惯用方式是什么?
解决方案
我不确定我是否理解seedDate
这里的目的。但我认为您过于依赖事件(一种 UIKit 方式)而不是单一事实来源原则(SwiftUI 方式)。
更新:添加了一种取消日期版本的方法。在这种情况下,编辑器视图应该Binding
只在保存时改变。为此,它使用State
将用于日期选择器的私有。这样,事实的来源被保留,因为使用的私有状态永远不会离开编辑视图的上下文。
struct ContentView: View {
@State var dateEditorVisible = false
@State var date: Date = Date() // source of truth
var body: some View {
NavigationView {
VStack {
Text("\(date.format("HH:mm:ss"))")
Button(action: self.showDateEditor) {
Text("Edit")
}
.sheet(isPresented: $dateEditorVisible) {
// Here we provide a two way binding to the `date` state
// and a way to dismiss the editor view.
DateEditorView(date: self.$date, dismiss: self.hideDateEditor)
}
}
}
}
func showDateEditor() {
dateEditorVisible = true
}
func hideDateEditor() {
dateEditorVisible = false
}
}
struct DateEditorView: View {
// Only a binding.
// Updating this value will update the `@State date` of the parent view
@Binding var date: Date
@State private var editingDate: Date = Date()
private var dismiss: () -> Void
init(date: Binding<Date>, dismiss: @escaping () -> Void) {
self._date = date
self.dismiss = dismiss
// assign the wrapped value as default value for edition
self.editingDate = date.wrappedValue
}
var body: some View {
VStack {
DatePicker(selection: $editingDate, displayedComponents: .hourAndMinute) {
Text("Date")
}
HStack {
Button(action: self.save) {
Text("Save")
}
Button(action: self.dismiss) {
Text("Cancel")
}
}
}
}
func save() {
date = editingDate
dismiss()
}
}
通过这种方式,您无需定义保存操作来更新父视图或使当前值与某些默认值保持同步。你只有一个单一的事实来源来驱动你的所有 UI。
编辑:
Date
使其构建的扩展。
extension Date {
private static let formater = DateFormatter()
func format(_ format: String) -> String {
Self.formater.dateFormat = format
return Self.formater.string(from: self)
}
}
推荐阅读
- jenkins - jenkinsfile 页面加载事件
- javascript - 为什么我的 Ajax 调用没有超过 readystate 1?
- r - 如何计算R中数据框中每行出现多个字符串的次数
- jestjs - Jest 在测试期间没有显示绿色进度条
- python - TypeError:“模块”对象在 Python 3 中不可调用
- c++ - 在 C++ 中使用共享内存时出现 SIGSEGV 错误
- html - 页脚高度不固定的问题
- shell - 循环并组合两个文本文件的脚本
- javascript - 将纯 li 文本随机转换为纯 JavaScript 的可点击链接
- asp.net - 如何从主 ASPX 页面跳转到子 aspx 页面上的特定部分 (div)