SwiftUI - 更新@State 不会改变视图
Posted
技术标签:
【中文标题】SwiftUI - 更新@State 不会改变视图【英文标题】:SwiftUI - updating @State is not changing the view 【发布时间】:2020-11-03 10:21:08 【问题描述】:我是 SwiftUI 的新手,我想创建一个带有“快速开发人员访问”按钮(又名“User1”)的登录屏幕,它应该填写用户和密码字段。
当我点击“User1”按钮时,LoginScreen
的@State
电话和密码变量正确填充了正确的值,但CustomLoginField
没有显示更新后的值。
我也尝试使用@Binding var phone:String
代替@State
,但结果相同。
我知道@State
应该是私有的。所以我也想知道编写代码的正确方法。
import SwiftUI
struct LoginScreen: View
private let developers:[User] = [
.init(name: "User1", phone: "12345678", password: "1234")]
private let minSpaceFromBottom:CGFloat = 30
@State fileprivate var phone:String = ""
@State fileprivate var password:String = ""
var body: some View
GeometryReader geo in
ZStack
Color(#colorLiteral(red: 0.9965313077, green: 0.9966740012, blue: 0.9965001941, alpha: 1))
VStack(alignment: .center)
Spacer().frame(height: geo.safeAreaInsets.top)
CustomLoginField(inputStr:phone, keyboard: .numberPad, placeholder:"PHONE", formatedPhoneNumber:true, maxLength: 10)
CustomLoginField(inputStr:password, keyboard: .numberPad, placeholder: "PASSWORD", isSecure: true, maxLength: 4)
HStack
ForEach(developers, id:\.id) developer in
Text(developer.name!)
.frame(width: 70, height: 35, alignment: .center)
.onTapGesture
phone = developer.phone
password = developer.password
Spacer()
.frame(width: geo.size.width * 0.9, alignment: .leading)
Spacer()
.frame(height: minSpaceFromBottom)
private struct CustomLoginField: View
@State var inputStr:String
var keyboard:UIKeyboardType = .default
var placeholder:String
var isSecure:Bool = false
var formatedPhoneNumber = false
var maxLength = 0
var underlineColor:UIColor
let underlineOnColor = UIColor(.blue)
let underlineOffColor:UIColor = .lightGray
return inputStr.count >= maxLength ? underlineOnColor : underlineOffColor
var body: some View
VStack(alignment:.leading, spacing:-8)
Text(placeholder)
.opacity(!inputStr.isEmpty ? 1 : 0)
.animation(Animation.easeIn(duration: !inputStr.isEmpty ? 0.3 : 0))
if isSecure
SecureField(placeholder, text: $inputStr)
.modifier(CustomTextFieldModifire(parent: self))
else
TextField(placeholder, text: $inputStr)
.modifier(CustomTextFieldModifire(parent: self))
Color(underlineColor)
.frame(width: UIScreen.main.bounds.width * 0.88, height: 1)
.animation(Animation.easeIn(duration:0.3))
private struct CustomTextFieldModifire: ViewModifier
var parent:CustomLoginField
func body(content: Content) -> some View
content
.frame(height: 45)
.keyboardType(parent.keyboard)
.onReceive(parent.inputStr.publisher.collect())
var result = String($0)
if parent.maxLength > 0 && result.count > parent.maxLength
result = String(result.prefix(parent.maxLength))
parent.inputStr = result
private struct User:Identifiable
let id = UUID()
var name:String?
var phone:String
var password:String
struct LoginScreen_Previews: PreviewProvider
static var previews: some View
LoginScreen()
.previewDevice("iPhone 8")
【问题讨论】:
【参考方案1】:你只是犯了一个小错误。
在customloginField中,需要定义inputStr:String作为绑定变量
@Binding var inputStr:String
在使用时,你必须按照以下方式使用它
CustomLoginField(inputStr:self.$phone, keyboard: .numberPad, placeholder:"PHONE", formatedPhoneNumber:true, maxLength: 10)
CustomLoginField(inputStr:self.$password, keyboard: .numberPad, placeholder: "PASSWORD", isSecure: true, maxLength: 4)
在电话和密码前注意到“$”?
检查下面的 SO 线程以查看 @state 与 @binding SwiftUI @State vs Binding
【讨论】:
以上是关于SwiftUI - 更新@State 不会改变视图的主要内容,如果未能解决你的问题,请参考以下文章
在 SwiftUI 中使用 @State 属性包装器未更新视图
无法更新/修改 SwiftUI 视图的 @state var