1

I have one text field with place holder called letschat. Now whenever I start typing in my textfield, I want to show my textfield as some @letschat. When my textfield is empty that time my placeholder have to show. That I did. But I want to set whenever I start typing in my textfield. Whatever I am typing with that I want this text also to visible like:

Some @Lletschat

How can I do this?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
doubtman
  • 61
  • 13
  • Where do you want this text to be appeared? Under the typed one? – Daniyar Aug 14 '17 at 05:35
  • @Astoria YEAH...i measn...when i finish type my textfield and if no text in my text field.That time my place holder shoyld show...when i start typing my placeholder should hide...And if i type `a`.then automatically i have to see like `a@letschat`. Same if i type more word like `adasd@letschat` have to be visible in text field – doubtman Aug 14 '17 at 05:39

5 Answers5

1

I created a UITextField subclass that uses the placeholder (if set) as a suffix. As far as I can see everything works as expected. Maybe there are some tweaks needed to suit your needs.

Feel free to ask if anything is unclear:

class SuffixTextField: UITextField {

    override init(frame: CGRect) {
        super.init(frame: frame)
        sharedInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        sharedInit()
    }

    private func sharedInit() {
        addTarget(self, action: #selector(textChanged), for: .editingChanged)
    }

    override var text: String? {
        didSet {
            selectedTextRange = maxTextRange
        }
    }

    override var attributedText: NSAttributedString? {
        didSet {
            selectedTextRange = maxTextRange
        }
    }

    @objc private func textChanged() {
        if let currentText = text, let placeholder = placeholder {
            if currentText == placeholder {
                self.text = nil
            } else if !currentText.hasSuffix(placeholder) {
                self.text = currentText + placeholder
            }
        }
    }

    private var maxCursorPosition: UITextPosition? {
        guard let placeholder = placeholder, !placeholder.isEmpty else { return nil }
        guard let text = text, !text.isEmpty else { return nil }
        return position(from: beginningOfDocument, offset: (text as NSString).range(of: placeholder, options: .backwards).location)
    }

    private var maxTextRange: UITextRange? {
        guard let maxCursorPosition = maxCursorPosition else { return nil }
        return textRange(from: maxCursorPosition, to: maxCursorPosition)
    }

    override var selectedTextRange: UITextRange? {
        get { return super.selectedTextRange }
        set {
            guard let newRange = newValue,
                let maxCursorPosition = maxCursorPosition else {
                    super.selectedTextRange = newValue
                    return
            }

            if compare(maxCursorPosition, to: newRange.start) == .orderedAscending {
                super.selectedTextRange = textRange(from: maxCursorPosition, to: maxCursorPosition)
            } else if compare(maxCursorPosition, to: newRange.end) == .orderedAscending {
                super.selectedTextRange = textRange(from: newRange.start, to: maxCursorPosition)
            } else {
                super.selectedTextRange = newValue
            }
        }
    }

}

here you can see a preview: https://www.dropbox.com/s/etkbme37wuxbw1q/preview.mov?dl=0

André Slotta
  • 13,774
  • 2
  • 22
  • 34
  • i have used ur code solution with place holder value..but ist not at all reflecting ...can u please share that code ..so that , it will b helpfull – doubtman Aug 17 '17 at 06:07
  • There is no more code. You simply have to create a `SuffixTextField` programmatically or add a textfield in storyboard and set its custom class to `SuffixTextField`. – André Slotta Aug 17 '17 at 06:46
0

Conform your class to UITextfieldDelegate and then assign textfield.delegate = self

Now, add this Delegate Method, if you want your @letschat to be appended after user endtyping.

func textFieldDidEndEditing(textField: UITextField) {
    textField.text = "\(textField.text)@letschat"
}

or if you want it at the typing time.

textField.addTarget(self, action: #selector(YourViewController.textFieldDidChange(_:)), forControlEvents: UIControlEvents.EditingChanged)

func textFieldDidChange(textField: UITextField) {
    if textField.containsString("@letschat")  {
        textField.text = textField.text.stringByReplacingOccurrencesOfString("@letschat", withString: "")
    }

    textField.text = "\(textField.text)@letschat"

}

Hope this helps.

Daniyar
  • 2,975
  • 2
  • 26
  • 39
Aditya Srivastava
  • 2,630
  • 2
  • 13
  • 23
0

You can take the action of UITextField textFieldDidChange and get the call of every time when the textField text changed.

Just like that:

func textChangedAction(sender:UITextFiled) {
   if sender.text.rangeOfString("@Lletschat") != nil{ 
       sender.text = sender.text.replacingOccurrences(of: "@Lletschat", with: "")  
   }
   sender.text = "\(sender.text!) @Lletschat"
}

If you want to changed the color of your specific text you can check here.

Salman Ghumsani
  • 3,647
  • 2
  • 21
  • 34
0

Implement textfield delegate like this-

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    textField.text = textField.text?.replacingOccurrences(of: " @\(textField.placeholder!)", with: "", options: .literal, range: nil)
    textField.text?.append(string)
    textField.text?.append(" @\(textField.placeholder!)")

    return false
}
Abhishek Jain
  • 4,557
  • 2
  • 32
  • 31
0

Simple solution:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let newRange = textField.text?.range(from: range), let result = textField.text?.replacingCharacters(in: newRange, with: string) else { return true }
    if result.endsWithString("@letschat") {
        return true
    } else {
        textField.text = result + "@letschat"
        let position = textField.position(from: textField.beginningOfDocument, offset: result.characters.count)!
        textField.selectedTextRange = textField.textRange(from: position, to: position)
        return false
    }
}

With helper extension:

extension String {

    func range(from oldOne: NSRange) -> Range<String.Index>? {
        guard
            let from16 = utf16.index(utf16.startIndex, offsetBy: oldOne.location, limitedBy: utf16.endIndex),
            let to16 = utf16.index(utf16.startIndex, offsetBy: oldOne.location + oldOne.length, limitedBy: utf16.endIndex),
            let from = from16.samePosition(in: self),
            let to = to16.samePosition(in: self)
            else { return nil }
        return from ..< to
    }

    func endsWithString(_ string: String) -> Bool {
        guard characters.count >= string.characters.count else { return false }
        let index = self.index(startIndex, offsetBy: characters.count - string.characters.count)
        let substring = self.substring(from: index)
        return substring == string
    }
}

Difficult but clear solution is to create your own UIControl-subclass with UITextField and UILabel children views:

+-----------+         +-----------+
| textfield | -(3px)- | @letschat |
+-----------+         +-----------+

Use autolayout to keep the distance of 3 pixels between it. Don't forget to configure your class to send all the incoming actions to the textfield. You can use different font colours for these controls so user won't be confused about efforts to change label's value.

Daniyar
  • 2,975
  • 2
  • 26
  • 39
  • @Astoria.Ya its work.But once i start edit its showing , thats fine..but when i cancel all the text and no text i means not even a single letter in text field..Then my placeholder have to show .But now still that` @letschat ` si showing. How can i achieve that – doubtman Aug 14 '17 at 07:41
  • @doubtman try to play around with `if result == "@letschat" { // set nil value and return false }` – Daniyar Aug 14 '17 at 08:04
  • And "@letschat" shoyld not be editable. And i place place the marker at back of "@letschat" again one more "@letschat" is also adding – doubtman Aug 14 '17 at 08:11
  • aslo i tried this too...`if result == "@letschat" { textField.text = "" return false }` when no values in textfield.Still that "@letschat" is shwoing – doubtman Aug 14 '17 at 08:12
  • Then you definitely need to implement difficult solution because there are too much `if` cases. – Daniyar Aug 14 '17 at 08:15
  • Tried with Autolayout. Placed a label on the right of UITextField, but as we keep typing in UITextField the size of the text field is more compared to the position of the last character. Hence getting a gap between UItextField and UILabel. Is there any way we can get the position of the last character in text field relative to its super view? – SanjayPathak Apr 12 '19 at 06:58