我一直在使用SwiftUI和Combine,并且感觉好像有一种方法可以在视图中保留现有的@State属性并创建一个新属性。
例如,我有一个密码创建视图,其中包含用户的密码和passwordConfirm字段。我想采用这两个@State属性,并派生一个新的@State,可以在我的视图中使用它来断言输入是否有效。因此,为简单起见:不能为空且不相等。
Apple文档在绑定上说there is a publisher,尽管我似乎看不到它。
这是一些无效的伪代码:
import SwiftUI
import Combine
struct CreatePasswordView : View {
@State var password = ""
@State var confirmation = ""
lazy var valid = {
return self.$password.publisher()
.combineLatest(self.$confirmation)
.map { $0 != "" && $0 == $1 }
}
var body: some View {
SecureField($password, placeholder: Text("password"))
SecureField($confirmation, placeholder: Text("confirm password"))
NavigationButton(destination: NextView()) { Text("Done") }
.disabled(!valid)
}
}
发现任何人。 /如果可能的话,采取适当的方法?
更新Beta 2:
从beta 2发布者开始可用,因此该代码的前半部分现在可以使用。在视图中使用结果发布者的后半部分我仍然不知道(disabled(!valid)
)。
import SwiftUI
import Combine
struct CreatePasswordView : View {
@State var password = ""
@State var confirmation = ""
lazy var valid = {
Publishers.CombineLatest(
password.publisher(),
confirmation.publisher(),
transform: { String($0) != "" && $0 == $1 }
)
}()
var body: some View {
SecureField($password, placeholder: Text("password"))
SecureField($confirmation, placeholder: Text("confirm password"))
NavigationButton(destination: NextView()) { Text("Done") }
.disabled(!valid)
}
}
谢谢。
答案 0 :(得分:2)
由于@State/@Published
目前处于测试阶段,所以我不会玩Combine
,但这是您要实现的目标的简单解决方法。
我将实现一个视图模型来保存密码,密码确认以及密码是否有效
class ViewModel: NSObject, BindableObject {
var didChange = PassthroughSubject<Void, Never>()
var password: String = "" {
didSet {
didChange.send(())
}
}
var passwordConfirmation: String = "" {
didSet {
didChange.send(())
}
}
var isPasswordValid: Bool {
return password == passwordConfirmation && password != ""
}
}
通过这种方式,只要密码或确认更改,视图就会重新计算。
然后我将对视图模型进行@ObjectBinding
。
struct CreatePasswordView : View {
@ObjectBinding var viewModel: ViewModel
var body: some View {
NavigationView {
VStack {
SecureField($viewModel.password,
placeholder: Text("password"))
SecureField($viewModel.passwordConfirmation,
placeholder: Text("confirm password"))
NavigationButton(destination: EmptyView()) { Text("Done") }
.disabled(!viewModel.isPasswordValid)
}
}
}
}
我不得不将视图放在NavigationView
中,因为如果NavigationButton
不在其中之一中,则似乎无法启用自身。
答案 1 :(得分:0)
这里你需要的是一个计算属性。顾名思义,每次访问该属性时都会重新计算其值。如果您使用 @State
变量来计算属性,则每当 valid
更改时,SwiftUI 都会自动重新计算 View 的主体:
struct CreatePasswordView: View {
@State var password = ""
@State var confirmation = ""
private var valid: Bool {
password != "" && password == confirmation
}
var body: some View {
SecureField($password, placeholder: Text("password"))
SecureField($confirmation, placeholder: Text("confirm password"))
NavigationLink(destination: NextView()) { Text("Done") }
.disabled(!valid)
}
}