MacOS 11 上的 SwiftUI
目標是讓 SwiftUI SecureField 顯示不同于默認專案符號 (??????) 的 Unicode 字符,例如表情符號、隨機生成的字符等。目標的一個重要部分是實際的文本輸入由用戶完全可編輯和保留,并且可以在@State變數中訪問,并且僅顯示屏蔽字符,但我不介意它是通過 TextField 還是其他一些視圖來實作的。
例如,香草 SecureField 專案符號:
struct ContentView : View {
@State var password : String = ""
var body: some View {
VStack {
SecureField("Password", text: $password)
Button("Transmogrify!") {}
}.padding()
}
}
這導致:

目標是實作與 SecureField 相同的行為,但顯示不同的字符,如下所示:

到目前為止,我還沒有想出一個有效的代碼示例。我曾嘗試將普通TextField與顯式結合使用Binding<String>來嘗試控制底層文本get/set但由于系結的性質會影響最終存盤在password
uj5u.com熱心網友回復:
你可以用代理來做
import SwiftUI
//Shows a sample use
struct SecureParentView: View{
@State var text: String = "secure"
var body: some View{
VStack{
Text(text)
MySecureFieldView(text: $text)
}
}
}
//The custom field
struct MySecureFieldView: View {
@Binding var text: String
//The proxy handles the masking
var proxy: Binding<String>{
Binding(get: {
//Replace the return value
var result = ""
for _ in 0..<text.count{
let char: Character = "\u{272A}"
result.append(char)
}
return result
}, set: { value in
if value.isEmpty{
text = value
} else if value.count < text.count{
//If the user deletes more than 1 character
if text.count - value.count == 1{
text.removeLast()
}else{
text = ""
}
} else if value.count > text.count{
//If the user adds more than 1 character
if value.count - text.count == 1{
let new = (value.last?.description) ?? ""
text.append(contentsOf: new)
}else{
text = ""
}
}
})
}
var body: some View {
TextField("test", text: proxy)
}
}
struct SecureParentView_Previews: PreviewProvider {
static var previews: some View {
SecureParentView()
}
}

對于 iOS 15、MacCatalyst 15 和 macOS 12,有一個稍微更好的解決方案。
//The custom field
@available(iOS 15.0, macOS 12.0, *)
struct MySecureFieldView: View {
@Binding var text: String
//The proxy handles the masking
var proxy: Binding<String>{
Binding(get: {
//Replace the return value
var result = ""
for _ in 0..<text.count{
let char: Character = "\u{272A}"
result.append(char)
}
return result
}, set: { value in
//Not needed here because the TextField is focused
})
}
@FocusState private var focusedField: Int?
var body: some View {
//This is for size. The 3 layers have to match so the cursor doesn't look off
Text(text)
.overlay(
ZStack{
//This is the regular textfield to hold the data
TextField("actual", text: $text)
.foregroundColor(Color(UIColor.clear))
.focused($focusedField, equals: 1)
//This will sit on top and is the only one that has color
//It will reduce in size to match lettering
Text(proxy.wrappedValue)
.minimumScaleFactor(0.2)
.foregroundColor(Color(UIColor.label))
}
)
.foregroundColor(Color(UIColor.clear))
.textSelection(.disabled)//You likely dont want this
.onTapGesture {
focusedField = 1
}
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/334412.html
