我将以下代码用于输入字段,用户可以在其中输入API令牌。默认情况下,它显示为SecureField,但用户可以单击“眼睛”图标并更改为常规字段
struct PasswordField : View {
@Binding var value : String
@State var showToken: Bool = false
var body : some View {
if(showToken){
ZStack(alignment: .trailing) {
TextField(text: $value) {
Text("API Token").bold().padding(EdgeInsets(top: 0, leading: 44, bottom: 0, trailing: 0))
}
Image(systemName: "eye").onTapGesture {
showToken.toggle()
}.padding(.trailing,5)
}
} else {
ZStack(alignment: .trailing) {
SecureField(text: $value) {
Text("API Token").bold().padding(EdgeInsets(top: 0, leading: 44, bottom: 0, trailing: 0))
}
Image(systemName: "eye.slash").onTapGesture {
showToken.toggle()
}.padding(.trailing,5)
}
}
}
}
它可以像我写的那样工作,但是我讨厌if和else块中几乎完全相同的代码。唯一的区别是一个是TextField,另一个是SecureField,以及显示的图标,eye与eye.slash。我如何重构它以减少代码重复?
我尝试创建另一个只包含重复代码的视图,但是我不知道如何指定是使用TextField还是SecureField。
protocol MyProtocol {}
extension SecureField : MyProtocol {}
extension TextField: MyProtocol {}
struct InnerView<T> : View where T:MyProtocol {
@Binding var value : String
@Binding var showToken: Bool
var icon : String
var body : some View {
ZStack(alignment: .trailing) {
T(text: $value) {
Text("API Token").bold().padding(EdgeInsets(top: 0, leading: 44, bottom: 0, trailing: 0))
}
Image(systemName: icon).onTapGesture {
showToken.toggle()
}.padding(.trailing,5)
}
}
}
问题是MyProtocol没有正确的init,所以我添加了与TextField和SecureField中相同的init
protocol MyProtocol {
init(text: Binding<String>, prompt: Text?, @ViewBuilder label: () -> Label)
}
但是Label
本身是一个泛型,这就是我陷入死胡同的地方。
我对Swift相当陌生,但我确实有很多编程经验。虽然我来自使用PHP,Javascript等的Web开发世界。
1条答案
按热度按时间wgeznvg71#
使用上面lorem ipsum链接到的答案中的示例,我得出了下面的解决方案,该解决方案非常符合我的喜好