最大输入后禁用 UITextField 光标移动

Disable UITextField cursor movement after max input

我为固定大小的输入创建了自定义 UITextField 组件。 TextField 的宽度、字体大小、字距调整和字符数都是固定的。我可以阻止用户输入超过 8 个字符(见下面的 shouldChangeCharactersIn 方法),但是在第 8 个字符之后,光标自动移动到下一个位置,这会产生以下问题。

我想显示所有输入的字符而不减小它们的大小。所以

[ 1 2 3 4 5 6 7 8 ] should be shown instead of [ 2 3 4 5 6 7 8 | ]

我试图将光标放在第 8 个字符的右侧,但这会改变所有字距调整并影响所有其他字符。

正确的处理方法是什么?我应该如何防止光标移动,以便 UITextField 不会正确滚动?

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let textFieldText = textField.text,
        let rangeOfTextToReplace = Range(range, in: textFieldText),
        !string.containsSpecialCharacters else {
            return false
    }
    let substringToReplace = textFieldText[rangeOfTextToReplace]
    let count = textFieldText.count - substringToReplace.count + string.count

    return count <= 8
}

如果您尝试此代码会发生什么?

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
    if range.location < 8 {
        return true
    }
    // return NO to not change text
    return false
}

试试下面的代码:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if textField.text?.count ?? 0 <= 7{
            if textField.text?.count ?? 0 == 7{
                DispatchQueue.main.async {
                    textField.resignFirstResponder()
                }
            }
            return true
        }
        textField.resignFirstResponder()
        return false
    }

在 viewController 的 viewDidLoad 方法中将 customTextField 的委托设置为自己,并确认 UITextFieldDelegate 协议

我通过更改最后一个字符后的紧排解决了这个问题。所以现在,光标不再跳跃 40pt,而是只跳跃 1pt(或者你在下面的方法中设置的任何值)

@objc private func textFieldDidChange() {

    guard let text = textField.text else { return }

    if text.count == Constant.deviceCodeCharacterCount {
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(.kern, value: Constant.deviceCodeCharacterSpacing, range: NSRange(location: 0, length: text.count - 1))
        attributedString.addAttribute(.kern, value: 1, range: NSRange(location: Constant.deviceCodeCharacterCount - 1, length: 1))
        textField.attributedText = attributedString
    }
}