【问题标题】:SwiftUI change SecureField masking characterSwiftUI 更改 SecureField 掩码字符
【发布时间】:2021-12-09 23:06:36
【问题描述】:

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 中的文本

【问题讨论】:

    标签: swift macos swiftui


    【解决方案1】:

    你可以通过代理来做到这一点

    import SwiftUI
    //Shows a sample use
    @available(iOS 15.0, macOS 12.0, *)
    struct SecureParentView: View{
        @State var text: String = "secure"
        var body: some View{
            VStack{
                Text(text)
                MySecureFieldView(text: $text)
            }
        }
    }
    //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: {
                return text.map { _ in "\u{272A}" }.joined() 
            }, 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).lineLimit(1)
                .opacity(0)
            //Put a true secure field on top that has invisible text/dots
                .overlay(
                    SecureField("actual", text: $text)
                        .foregroundColor(Color.clear)
                        .focused($focusedField, equals: 1)
                        .minimumScaleFactor(0.2)
                    
                )
                .background(
                    //This will sit on below but will look like it is on top
                    //It will reduce in size to match lettering
                    Text(proxy.wrappedValue)
                        .lineLimit(1)
                        .minimumScaleFactor(0.2)
                        .foregroundColor(Color(UIColor.label))
                        .opacity(1)
                )
                .foregroundColor(Color(UIColor.clear))
                .onTapGesture {
                    focusedField = 1
                }
        }
        
    }
    
    @available(iOS 15.0, macOS 12.0, *)
    struct SecureParentView_Previews: PreviewProvider {
        static var previews: some View {
            SecureParentView()
        }
    }
    

    【讨论】:

    • 首先感谢您的回答,这对我的理解有很大帮助!如果用户在末尾输入字符或在输入末尾删除字符,则此解决方案非常有效。但是,如果执行更复杂的输入,例如在输入的中间插入一个字符,或者在字符串的任意部分复制和粘贴序列,就会出现问题。您是否熟悉一种可以优雅地解释这些问题的方法?我可以设计一个字符串比较器算法,但这对于这个目标来说似乎有点复杂。
    • @batanasov 是的,这需要更多的思考。就像从值中找到字母字符一样。这就是为什么我在变化不止一个时清除字符串。您还可以在特殊字符之间添加对 alpha 的检查,然后将其清除。也许添加显示密码的选项。通常,当人们进行特殊更改时,他们会显示密码。这仅取决于您要投入多少工作。
    • @batanasov 我添加了 iOS 15 macOS 12 版本。它稍微好一点。 TextField 是专注的,因此在更多情况下它会表现得更好,但复制和粘贴不起作用。可能需要一点定制
    • 这很好(它有效!)但我建议稍微完善一下。例如,绑定获取可以简化为text.map { _ in "\u{272A}" }.joined()String(repeating: "\u{272A}", count: text.count)
    • @batanasov 我正在做其他事情并想出了一个更好的版本。光标效果更好。
    猜你喜欢
    • 2020-03-16
    • 2012-12-12
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    相关资源
    最近更新 更多