简体   繁体   中英

Swift 3: Append to UITextField while Editing Changed

Probably a simple one although no answers updated for Swift 3.

How can I append characters to a UITextField while the textfield is being edited? The characters should be appended while the user types not after the editing ends.

For example:

User types: 1
Field Updates: 1 kg

User types 123
Field Updates: 123 kg

Was trying to tackle this using EditingChanged IBActions but how can I stop the value from appending "kg" for each new character that is typed?

Example "1 kg 2 kg 3 kg" 

Try this way it may help you out.

  1. Add target for textfield on text is being editing

     textField.addTarget(self, action: #selector(self.textFieldDidChange), for: .editingChanged) 
  2. In Observer method try the following way

     func textFieldDidChange(textfield: UITextField) { var text = textField.text?.replacingOccurrences(of: " KG", with: "") text = text! + " KG" textField.text = text print("Text changed") } 

You want the UITextFieldDelegate method

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool

I should warn you that this is incredibly irritating to implement because of the way Swift handles Strings. Its usually better to just cast the text to NSString (which is UTF16) and deal with the range that way. However if you are just doing numbers and can live with a fixed decimal place the case is much easier to handle. Keep a custom number that represents your "real number" and just update the field to reflect your formatted number. Since you only allow digits there are finitely many cases to handle (this code will not handle copy/paste).

You must set the textfield delegate and keyboard (to numeric) in the storyboard.

    class ViewController: UIViewController{
        @IBOutlet weak var textField: UITextField!
        fileprivate let digits: Set<String> = ["0","1","2","3","4","5","6","7","8","9"]
        fileprivate let decimalPlaces = 2
        fileprivate let suffix = " kg"
        fileprivate lazy var formatter: NumberFormatter = {
            let formatter = NumberFormatter()
            formatter.numberStyle = .decimal
            formatter.minimumFractionDigits = self.decimalPlaces
            formatter.maximumFractionDigits = self.decimalPlaces
            formatter.locale = NSLocale.current
            return formatter
        }()
        fileprivate var amount: Int = 0

        override func viewDidLoad() {
            super.viewDidLoad()

        }
    }

    extension ViewController: UITextFieldDelegate {
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

            if digits.contains(string) {
                amount *= 10
                amount += Int(string)!
            } else if string == "" {
                amount /= 10
            }

            guard amount > 0 else {
                textField.text = ""
                return false
            }

            let digitsAfterDecimal = formatter.maximumFractionDigits
            var value = Double(amount)
            for _ in 0..<digitsAfterDecimal {
                value /= 10
            }
            textField.text = formatter.string(from: NSNumber(value: value))! + suffix

            return false
        }

    }

Use UITextFieldDelegate's function:

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool // return NO to not change text

You'll have to combine the text from the textfield.text and string parameter from this function using the range parameter to get the string To Be formed on textfield while you type/paste/clear based on range.

Keep track on range.length as it always gives the count of string being deleted/cleared and is 0 when you enter text. And range.location gives the position of edit.

Then you can set the formed string to textfield.text and return false Remember - return false and not true

Conform the textfield delegate to the controller and try this solution.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if string == "" {
        // handle backspace scenario here
      return true
    } else if var textString = textField.text {
        let unitString = "kg"
        if textString.contains(unitString) {
            textString = textString.replacingOccurrences(of: unitString, with: "")
            textString += string + unitString
            textField.text = textString
        } else {
            textField.text = string + unitString
        }
        return false
    }
    return true
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM