Swift 5 - 用 X 屏蔽文本字段文本

Posted

技术标签:

【中文标题】Swift 5 - 用 X 屏蔽文本字段文本【英文标题】:Swift 5 - Mask Textfield Text with X 【发布时间】:2021-03-18 12:14:29 【问题描述】:

我想要实现的是, TextField 格式应为 XXXX XXXX XXXX 当用户点击显示按钮时,它应该显示文本 1234 5678 9123

下面是我能够实现 1234 5678 9123 格式的代码,屏蔽和存储原始数据待定。

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool

        if textField.tag == 0 || textField.tag == 1 
        if string.isBackspace
        
            if range.location == 5 || range.location == 10
            
                textField.text?.removeLast()
            
        
        
        if string == ""
            return true
        

        //range.length will be greater than 0 if user is deleting text - allow it to replace
        if range.length > 0
        
            return true
        

        //Don't allow empty strings
        if string == " "
        
            return false
        

        //Check for max length including the spacers we added
        if range.location > 13 //23
        
            return false
        

        var originalText = textField.text
        let replacementText = string.replacingOccurrences(of: " ", with: "")

        //Verify entered text is a numeric value
        let digits = NSCharacterSet.decimalDigits
        for char in replacementText.unicodeScalars
        
            if !(digits as NSCharacterSet).longCharacterIsMember(char.value)
            
                return false
            
        
        //Put an empty space after every 4 places
        if (originalText?.count)! > 0
        
            if (originalText?.count)! < 5 && (originalText?.count)! % 4 == 0
                originalText?.append(" ")
            else if(((originalText?.count)! + 1) % 5 == 0)
                originalText?.append(" ")
            

        

        textField.text = originalText
        
        
        //2 - Nick Name,3 - Recipient Name
        if textField.tag == 2 || textField.tag == 3 
            //Max Limit for Nick Name and Benificiary Name is 65
            if range.location > 64
            
                return false
            
        
        return true
    

【问题讨论】:

【参考方案1】:

如果我理解正确,您的要求是创建自定义安全文本字段。要求是:

用户最多可以输入 12 个符号 只允许数字 文本字段可能具有“屏蔽”和“正常”模式 显示的文本应通过将 4 个字符组合在一起来格式化 每组之间有一个空格 在“屏蔽”模式下,所有数字都替换为“X”符号 在正常模式下数字是可见的

此外,所有文本字段功能都可以正常工作,包括复制粘贴、选择、在文本中间插入代码……

我创建了一个新项目并很快以这个结束:

class ViewController: UIViewController 
    
    @IBOutlet private var textField: UITextField?
    
    private var actualText: String = ""
    private var maskedText: String = ""
    
    private var masked: Bool = true 
        didSet 
            refreshTextField()
        
    
    
    @IBAction private func maskedTogglePressed(_ sender: Any) 
        masked = !masked
    
    
    private func refreshTextField() 
        textField?.text = masked ? maskedText : actualText
    


extension ViewController: UITextFieldDelegate 
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 
        var newString = (actualText as NSString).replacingCharacters(in: range, with: string) // Apply new text
        
        // Remove all whitespaces
        newString = newString.replacingOccurrences(of: " ", with: "")
        // Remove all that is not a number
        newString = newString.filter("0123456789".contains)
        
        // Split string into components of max 4
        var components: [String] = 
            var toDeplete = newString
            var components: [String] = []
            while !toDeplete.isEmpty 
                let length = min(toDeplete.count, 4)
                components.append(String(toDeplete.prefix(length)))
                toDeplete.removeFirst(length)
            
            return components
        ()
        // Limit to maximum of 3 components
        if components.count > 3 
            components = Array(components[0..<3])
        
        
        // Generate masked components, replacing all characters with X
        let maskedComponents: [String] = components.map  String($0.map  character in return "X" ) 
        
        // Add spaces
        newString = components.joined(separator: " ")
        let maskedText = maskedComponents.joined(separator: " ")
        
        // Assign new strings
        self.actualText = newString
        self.maskedText = maskedText
        
        // Refresh field
        refreshTextField()
        
        // Disallow text field to apply it's change
        return false
    
    

在处理字符串时可以使用一些改进。但它确实有效。

代码已被注释,并应提供有关解决方案的更多信息。

【讨论】:

Matik 你理解了这个问题,但你的解决方案不起作用!!!你可以请测试然后发布。 它就像一个普通的文本字段和点击按钮只是重置文本字段。 @Eminem 我假设您忘记将文本字段委托分配给视图控制器。为了使其工作,您需要连接 textField 插座,您需要将 maskedTogglePressed 操作与按钮单击方法连接起来,并且您需要将您的文本字段委托分配给视图控制器。根据您的经验,除了指派代表之外,很可能所有这些都已完成。 是的,我复制粘贴了您的解决方案并分配了网点,顺便说一句,问题已解决。我会再次检查您的逻辑并让您知道谢谢您的时间。 @Eminem 我提出这个屏幕录像,按照你的描述进行,结果与你的不同:youtu.be/7DLjALOrypw【参考方案2】:

我终于可以解决这个问题了, 这是 Adwait Barkale 的解决方案。 有任何疑问请发邮件给我 adwaitbarkale@gmail.com

注意:- arrPersonalDetails[2].value 只是一个字符串(使用要存储输入的原始文本的变量)

1.UITextfield 委托

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
    
        if textField.tag == 0 || textField.tag == 1 
            //For Masking Numbers 1234 5678 9123 into XXXX XXXX XXXX
            //1.Storing original data 1234 5678 9123 into arrPersonalDetails[index].value
            //2.Formatting textfield by putting spaces after every 4 and 8 digit
            
            //Step 1 Store Data Locally
            if string.isBackspace
            
                if range.location == 5 || range.location == 10
                
                    textField.text?.removeLast()
                
                if arrPersonalDetails[textField.tag].value!.count == 11 || arrPersonalDetails[textField.tag].value!.count == 6
                
                    arrPersonalDetails[textField.tag].value!.removeLast()
                
            
            //Check for max length including the spacers we added
            if range.location > 13 //23
            
                return false
            
            
            if string.isBackspace
            
                if arrPersonalDetails[textField.tag].value!.count != 0 && arrPersonalDetails[textField.tag].value!.count != 11 || arrPersonalDetails[textField.tag].value!.count != 0 && arrPersonalDetails[textField.tag].value!.count != 6
                
                    let truncated = String(arrPersonalDetails[textField.tag].value!.dropLast())
                    arrPersonalDetails[textField.tag].value = truncated
                
             else 
                if arrPersonalDetails[textField.tag].value!.count == 4 || arrPersonalDetails[textField.tag].value!.count == 9
                
                    arrPersonalDetails[textField.tag].value!.append(" ")
                
                arrPersonalDetails[textField.tag].value!.append(string)
            
            let oValue = arrPersonalDetails[textField.tag].value
            arrPersonalDetails[textField.tag].value = oValue
            
            if string == ""
                return true
            
            
            //range.length will be greater than 0 if user is deleting text - allow it to replace
            if range.length > 0
            
                return true
            
            
            //Don't allow empty strings
            if string == " "
            
                return false
            
            
            //Step 2 - Manage Textfield Data
            var originalText = textField.text
            let replacementText = string.replacingOccurrences(of: " ", with: "")
            
            //Verify entered text is a numeric value
            let digits = NSCharacterSet.decimalDigits
            for char in replacementText.unicodeScalars
            
                if !(digits as NSCharacterSet).longCharacterIsMember(char.value)
                
                    return false
                
            
            //Put an empty space after every 4 places
            if (originalText?.count)! > 0
            
                if (originalText?.count)! < 5 && (originalText?.count)! % 4 == 0
                    originalText?.append(" ")
                else if(((originalText?.count)! + 1) % 5 == 0)
                    originalText?.append(" ")
                
                
            
            textField.text = originalText
        
        return true
    

2.将目标添加到文本字段

cell.tflData.addTarget(self, action: #selector(maskTextfield(tfl:)), for: .editingChanged)

/// Function to mask unmask textfiel's text
    /// - Parameter tfl: UITextfield
    @objc func maskTextfield(tfl: UITextField)
    
        let value = arrPersonalDetails[tfl.tag].value
        if showOriginalText //Change this value on your button click
        
            tfl.text = value
         else 
            //Masking numbers with X
            var maskedText = ""
            if value!.count != 0 
            for i in 1...value!.count 
                if i == 5 || i == 10 
                    maskedText.append(" ")
                 else 
                    maskedText.append("X")
                
            
            
            print("Masked Text = \(maskedText)")
            tfl.text = maskedText
        
    

编辑:-

注意:- 在文本字段中没有结束编辑不要写 someVariable = textField.text 否则需要 XXXX XXXX XXXX

改为这样写,

func textFieldDidEndEditing(_ textField: UITextField) 
        //Bank Account textfield
        if textField.tag == 2
        
            self.arrPersonalDetails[2].value = self.arrPersonalDetails[2].value
        
        //Re-enter Bank Account textfield
        if textField.tag == 3
        
            self.arrPersonalDetails[3].value = self.arrPersonalDetails[3].value
        
    

编码愉快!!!

【讨论】:

以上是关于Swift 5 - 用 X 屏蔽文本字段文本的主要内容,如果未能解决你的问题,请参考以下文章

在 HTML(5) 文本输入中屏蔽字符的最简单方法

IOS Swift WkWebview如何屏蔽长按

如何在密码字段中显示被屏蔽的单词密码?

屏蔽/禁止全选文本

QListWidget中字符后的屏蔽文本

如何在 netty4 中设置 Web 套接字客户端未屏蔽模式文本框