How to Make Text Typed in Textfield Undeletable

How to make text typed in TextField undeletable?

The idea is the create UITextField class and use UIViewRepresentable to bind with SwiftUI view. By this, you can use all delegate methods and detect backspace. Also, using this you can prevent from cut and delete from tap action.

UndeletableTextField custom class

class UndeletableTextField: UITextField {

// This for prevent to cut and delete
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.delete(_:)) ||
action == #selector(UIResponderStandardEditActions.cut(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}

UIViewRepresentable view

struct UndeletableTextFieldUI: UIViewRepresentable {

@Binding var text: String
var placeholder: String

func makeUIView(context: Context) -> UndeletableTextField {
let textField = UndeletableTextField(frame: .zero)
textField.delegate = context.coordinator
textField.placeholder = placeholder
return textField
}

func updateUIView(_ uiView: UndeletableTextField, context: Context) {
uiView.text = text
}

func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}

class Coordinator: NSObject, UITextFieldDelegate {
var parent: UndeletableTextFieldUI

init(parent: UndeletableTextFieldUI) {
self.parent = parent
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Here we detect backspace and ignore it.
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
return false
}
}
return true
}
}
}

ContentView

struct ContentView: View {
@State private var text: String = ""
var body: some View {
UndeletableTextFieldUI(text: $text, placeholder: "Type here")
}
}

Make portion of UITextView undeletable

sch's last edit makes a decent answer, but I want to offer a slightly more flexible approach.

You have to keep in mind the copy/paste system. User might select all the text in text field and try to paste in the entire value which might be perfectly acceptable, but if (range.location <= 9) { return NO; } will reject it. The way I'd do it is put together a string that would be a result of successful edit and then check if that string would start with your desired prefix.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSLog(@"resulting string would be: %@", resultString);
NSString *prefixString = @"blabla";
NSRange prefixStringRange = [resultString rangeOfString:prefixString];
if (prefixStringRange.location == 0) {
// prefix found at the beginning of result string
return YES;
}
return NO;
}

Edit: if you want to check if the current string in text field starts with the prefix, you can use rangeOfString: the same way:

NSRange prefixRange = [textField.text rangeOfString:prefixString];
if (prefixRange.location == 0) {
// prefix found at the beginning of text field
}

Adding text to UITextField you can't delete

You can implement this code in shouldChangeCharactersInRange delegate method.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField.text.length == 1 && [string isEqualToString:@""]) {//When detect backspace when have one character.
textField.text = @"myText";
}
return YES;
}

Swift: Limit Characters # in textField without disabling/interfering with other functions

You're being given the textField that is changing characters in the delegate function. Here, you can compare it to the specific fields that you want to limit:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
if !(textField == stuffOneTextField || textField == descriptionTextField) {
return true
}
let newLength = text.characters.count + string.characters.count - range.length
return newLength <= limitLength
}

Also, func textFieldShouldReturn(textField: UITextField!) -> Bool is giving you a text field, and you can call resignFirstResponder() on that, if that is what you want to do there.

How do I make a text input non-editable?

<input type="text" value="3" class="field left" readonly>

No styling necessary.

See <input> on MDN https://developer.mozilla.org/en/docs/Web/HTML/Element/input#Attributes

Uneditable prefix inside a UITextField using Swift

For the first part, you can refactor your delegate method as follow.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
//This makes the new text black.
textField.typingAttributes = [NSForegroundColorAttributeName:UIColor.blackColor()]
let protectedRange = NSMakeRange(0, 6)
let intersection = NSIntersectionRange(protectedRange, range)
if intersection.length > 0 {

return false
}
if range.location == 12 {
return true
}
if range.location + range.length > 12 {
return false
}
return true
}

This will lock down both the length at 13 and the prefix can not be deleted. Everything typed will be UIColor.blackColor()

Then you can a method like the following in your viewDidLoad, to set the prefix.

func makePrefix() {
let attributedString = NSMutableAttributedString(string: "C-TAD-")
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.lightGrayColor(), range: NSMakeRange(0,6))
textField.attributedText = attributedString
}


Related Topics



Leave a reply



Submit