Can i hide password in UITextView by * or any other symbol? I need to use UITextView instead of UITextField. I want to hide all characters of textView.
I like to share my own implementation after using the previous answers for a while in a chat-like app, where the UITextView
is constantly filled and emptied.
My UITextView
works as an entry of text for different kind of data types (phones, e-mails, etc.) and I did not want to create other UITextView
specifically for handling this scenario, so I decided to subclass it and restructure a little bit the code because I faced with circumstances that the logic breaks when using an external keyboard or changing the text
property programatically (doing the last one does not call the delegate method).
So first subclassing...
UITextView
subclassclass MyTextView: UITextView {
var isProtected = false // `true` for activate the password mode
var plainText: String! = String() // Variable to save the text when `isProtected`
override var text: String! {
get { return isProtected ? plainText : super.text }
set {
if !isProtected {
plainText = newValue
}
super.text = newValue
}
}
}
PS: The overriding of the text
property helps us to get always the plain text in the UITextView
without calling other variables.
Then, in the view controller where the delegate is implemented...
UITextViewDelegate
extension MyViewController: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if myTextView.isProtected {
myTextView.plainText = (myTextView.plainText as NSString).replacingCharacters(in: range, with: text) // Basically: when is in password mode, saves all written characters in our auxiliar variable
}
return true
}
func textViewDidChange(_ textView: UITextView) {
if myTextView.isProtected {
textView.text = String(repeating: "•", count: textView.text.count) // Change every letter written with the character "•"
}
}
}
Finally, you only need to toggle the isProtected
flag somewhere in MyViewController
and that`s it:
myTextView.isProtected = true //or `false`
Create a global variable for password string.
var passwordString = ""
Then set delegates of UITextView like:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
passwordString = ((passwordString ?? "") as NSString).replacingCharacters(in: range, with: text)
return true
}
func textViewDidChange(_ textView: UITextView) {
//replace character with * or anyother character
yourtextView.text = String(repeating: "*", count: (textView.text ?? "").count)
}
and dont forget to do this:
yourTextview.delegate = self
Using an UITextView
leaves the whole job of masking the text yourself. You also need to make sure you disable copying for security reasons. Set your delegate
property and handle this something on these lines:
var originalText: String?
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
originalText = ((originalText ?? "") as NSString).replacingCharacters(in: range, with: text)
return true
}
func textViewDidChange(_ textView: UITextView) {
textView.text = String(repeating: "*", count: (textView.text ?? "").count)
}
If you need to retrieve the value of the actual text that was input use the originalText
property.