I have a Text Field and I would like to replace the default dot character to something else when the password is hidden. Is there any way to do this easily?
Swift 5 ready to use, updated version of crifan answer:
import UIKit
class PasswordTextField: UITextField, UITextFieldDelegate {
var realText: String {
didSet {
updateMaskStr()
}
}
let maskChar: Character
init(
frame: CGRect = .zero,
maskChar: Character = "*"
) {
realText = ""
self.maskChar = maskChar
super.init(frame: frame)
setupActions()
setupDelegates()
}
private func setupActions() {
addTarget(self, action: #selector(textFiledEditingChanged(textField:)), for: .editingChanged)
}
private func setupDelegates() {
delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func updateMaskStr(){
//change real text to mask char
var maskStr = ""
for _ in realText {
maskStr += String(self.maskChar)
}
text = maskStr
}
@objc
private func textFiledEditingChanged(textField: UITextField) { updateMaskStr() }
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let curText = realText
let updatedStr:String = (curText as NSString).replacingCharacters(in: range, with: string)
realText = updatedStr
return false
}
}
based on Ron.Kliffer's idea, I have implemented workable full code:
//
// PasswordTextField.swift
// CrifanLibSwift
//
// Created by licrifan on 16/7/8.
// Copyright © 2016年 licrifan. All rights reserved.
//
import UIKit
class PasswordTextField: CommonTextField, UITextFieldDelegate {
var realText:String {
didSet {
print("self.text=\(self.text), realText=\(realText)")
updateMaskStr()
}
}
var maskChar:Character
init(frame: CGRect = CGRectZero, maskChar:Character = "*") {
print("frame=\(frame), maskChar=\(maskChar)")
self.realText = ""
self.maskChar = maskChar
super.init(frame: frame)
self.secureTextEntry = false
self.addTarget(self, action: #selector(self.textFiledEditingChanged(_:)), forControlEvents: UIControlEvents.EditingChanged)
self.delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func updateMaskStr(){
print("before update: self.text=\(self.text), self.realText=\(self.realText)")
//change real text to mask char
var maskStr = ""
for _ in self.realText.characters {
maskStr += String(self.maskChar)
}
self.text = maskStr
print("after update: self.text=\(self.text), self.realText=\(self.realText)")
}
func textFiledEditingChanged(textField: UITextField) {
print("textField=\(textField), textField.text=\(textField.text)")
updateMaskStr()
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
print("textField=\(textField), range=\(range), string=\(string)")
var allow = true
let curText = self.realText
let updatedStr:String = (curText as NSString).stringByReplacingCharactersInRange(range, withString: string)
if updatedStr.characters.count > LoginRegisterPasswordLengthMax {
print("password exceed max length \(LoginRegisterPasswordLengthMax)")
allow = false
}
if allow {
self.realText = updatedStr
}
print("curText=\(curText), updatedStr=\(updatedStr), self.realText=\(self.realText)")
return false
}
}
and in another view EditInfoView.swift
, to use it:
class EditInfoView: UIView {
var passwordTextField:PasswordTextField
init(editMode:EditInfoMode) {
self.passwordTextField = PasswordTextField()
self.addSubview(self.passwordTextField)
if self.passwordTextField.notHidden {
//5. password text
var passwordPlaceholder = "密码(6-20位)"
if self.editMode == .ChangeLoginPassword {
passwordPlaceholder = "旧密码(6-20位)"
} else if self.editMode == .ForgotPassword {
passwordPlaceholder = "输入新密码(6-20位)"
}
self.passwordTextField.placeholder = passwordPlaceholder
self.passwordTextField.returnKeyType = UIReturnKeyType.Go
// self.passwordTextField.secureTextEntry = true
constrain(passwordTextField, smsCodeTextField, phoneTextField) {passwordTextField, smsCodeTextField, phoneTextField in
passwordTextField.centerX == passwordTextField.superview!.centerX
passwordTextField.width == passwordTextField.superview!.width - 2 * LoginRegisterPaddingX
passwordTextField.height == CommonTextFieldHeight
if self.editMode == .ChangeLoginPassword {
passwordTextField.top == passwordTextField.superview!.top + EditInfoViewTopPadding
} else {
passwordTextField.top == smsCodeTextField.bottom + EditInfoViewCommonPaddingY
}
}
}
}
finally in a view controller EditInfoViewController.swift
to real use it:
isValid = validatePassword(self, alertPrefix: alertPrefix, passwordStr: self.editInfoView.passwordTextField.realText, doAlertWhenInvalid: doAlertWhenInvalid)
the final effect is:
2 options here:
Here's the code (will show the password as $$$$):
var password: String = ""
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
password = password+string
textField.text = textField.text+"$"
println("\(password)")
return false
}