I'm trying to make a function where when user enter a text in UITextField in the same moment label shows entered text.
How could I make it?
Like:
textField.text = "10"
Label.text = "\(textField.text) smthg" //. (10 smthg)
textField.text = "10.56"
Label.text = "\(textField.text) smthg" //. (10.56 smthg)
Implement UITextFieldDelegate and set it to textField.delegate property. From UITextFieldDelegate implement shouldChangeCharactersIn callback method that gets called everytime the user tries to change input in the textfield:
class MyViewController: UIViewController {
...
func viewDidLoad() {
super.viewDidLoad()
// set the textField's delegate to self
textField.delegate = self
}
}
extension MyViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// to be always updated, you cannot use textField.text directly, because after this method gets called, the textField.text will be changed
let newStringInTextField = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
yourLabel.text = "\(newStringInTextField) smthg"
return true
}
}
Using arguments of the function you can get a string that will appear in textField and you can set it as text in yourLabel.
You need to implement textfield's delegate method shouldChangeCharactersIn, it will be called when user start typing, delete a character from textfield, click on clear button appear at right side of textfield when there is text in textfield.
You can use Editing Changed Action for that textField
#IBAction func changeText(_ sender: UITextField) {
Label.text = "\(textField.text) smthg"
}
Related
I'm managing user actions in UITextField with func textFieldShouldReturn(_ textField: UITextField) -> Bool and it works perfectly but if I set textField.text = "String"
This is not being called, I also tried with IBActions like valueChanged and DidEndEditing with no success
Any idea how can I solve this?
The delegate methods are not called when you change the text property programmatically.
But when you change the property in code you know that and when the value changed.
For example write a common function
func updateTextField(with string: String) {
textField.text = string
doSomethingAfterTextChanged()
}
Or use a property observer which is called when the value of textFieldValue changed
var textFieldValue : String {
didSet {
textField.text = textFieldValue
doSomethingAfterTextChanged()
}
}
You can do that. Add this code in your viewDidLoad
yourTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControl.Event.editingChanged);
Add this function in your viewController
#objc func textFieldDidChange(_ textField: UITextField)
{
// you are done check your value do something
}
I’m working on an app that uses accessibility. When the user clicks in a UITextField and writes a letter, the textField.shouldChangeCharactersIn method gets called. This happens without problems when voiceOver is switched on or off. But if the users turns on the Braille Screen Input, the method textField.shouldChangeCharactersIn doesn’t get called.
Instead an error gets logged out:
[User Defaults] Couldn't write value for key
VoiceOverHandwritingWasNativeAutocorrectEnabled in
CFPrefsPlistSource<0x1d4107860> (Domain: com.apple.Accessibility,
User: kCFPreferencesCurrentUser, ByHost: No, Container: (null),
Contents Need Refresh: Yes): setting preferences outside an
application's container requires user-preference-write or
file-write-data sandbox access, switching to read-only
Can somebody explain what this means?
It can be reproduced easily with:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let text = UITextField(frame: CGRect(x: 20.0, y: 150.0, width: 200.0, height: 30.0))
text.delegate = self;
text.backgroundColor = .gray
self.view.addSubview(text)
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print("replacementString : \(string)")
return true
}
}
I think it's a bug on apple Api. This solution might not fit your use case but you may try something like this. Here is the alternate temporary solution to keep track of text using custom class inheriting Textfield.
class AccessibilityTextField: UITextField {
override func accessibilityElementDidLoseFocus() {
_ = delegate?.textFieldDidEndEditing?(self)
}
}
Then in your textfield delegate implementation method, validate the text to enable or disable some other button.
extension MyView: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
//Do you check here
}
}
Remember this is not live tracking of Text(like char in range) as didLoseFocus is called only once.
Make you textField Object global because it gets deallocated right after the execution of the method viewDidLoad
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
var textField: UITextField?
override func viewDidLoad() {
super.viewDidLoad()
textField = UITextField(frame: CGRect(x: 20.0, y: 150.0, width: 200.0, height: 30.0))
textField?.delegate = self;
textField?.backgroundColor = .gray
self.view.addSubview(textField!)
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print("replacementString : \(string)")
return true
}
}
so I am making UILabel live update from UiTextfield (user input). I am using the code from this thread Swift3: Live UiLabel update on user input
but somehow, my UILabel always left one character when I fully erase the text in my UITextField. like the .gif in here http://g.recordit.co/SPQWnYtHJg.gif
and it seems one character is always missing like the picture below
here is the code I use
import UIKit
class CreateEventVC: UIViewController {
#IBOutlet weak var eventNameTextField: UITextField!
#IBOutlet weak var eventNameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//initial value
eventNameLabel.text = " "
// delegate declaration
eventNameTextField.delegate = self
}
}
extension CreateEventVC : UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
eventNameLabel.text = eventNameTextField.text
return true
}
}
I initially suspect because I add this line in viewDidload
eventNameLabel.text = " "
but if i delete this one, the problem is still there
what should I do ?
textField:shouldChangeCharactersIn:range:replacementString is called before the change is applied to the text field, this allows your app to veto the request and filter out unwanted content.
The problem is, you're relying on the text field's text. Instead, you need build the resulting value from the information passed to the delegate and apply that
Maybe something more like...
extension CreateEventVC: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = textField.text ?? ""
eventNameLabel.text = (text as NSString).replacingCharacters(in: range, with: string)
return true;
}
}
class CreateEventVC: UIViewController {
#IBOutlet weak var eventNameTextField: UITextField!
#IBOutlet weak var eventNameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//initial value
eventNameLabel.text = " "
eventNameTextField.addTarget(self, action: #selector(onTextFieldTextDidChange), for: .editingChanged)
}
#objc func onTextFieldTextDidChange() {
eventNameLabel.text = eventNameTextField.text
}
}
Explanations:
We add target to the eventNameTextField which will call the onTextFieldTextDidChange func each time the textField text is changed.
I have a UITextField (that represents a tip value) in my Storyboard that starts out as $0.00. If the user types an 8, I want the textField to read $0.08. If the user then types a 3, I want the textField to read $0.83. If the user then types 5, I want the textField to read $8.35. How would I go about changing the input to a UITextField in this manner?
You can do this with the following four steps:
Make your viewController a UITextFieldDelegate by adding that to the class definition.
Add an IBOutlet to your textField by Control-dragging from the UITextField in your Storyboard to your code. Call it myTextField.
In viewDidLoad(), set your viewController as the textField’s delegate.
Implement textField:shouldChangeCharactersInRange:replacementString:.
Take the incoming character and add it to the tip, and then use the String(format:) constructor to format your string.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var myTextField: UITextField!
// Tip value in cents
var tip: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
myTextField.delegate = self
myTextField.text = "$0.00"
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let digit = Int(string) {
tip = tip * 10 + digit
textField.text = String(format:"$%d.%02d", tip/100, tip%100)
}
return false
}
}
Trying to disable/enable the next button (which begins disabled on the storyboard) based on how many characters are in the textView field. It isn't working, which makes me think that only the textField has this feature and not the textView (they were really lazy with developing the textView field).
I have an outlet connected for the textView and next button:
#IBOutlet weak var textView: UITextView!
#IBOutlet weak var nextButton: UIBarButtonItem!
func textView(textView: UITextView, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let oldText: NSString = textView.text
let newText: NSString = oldText.stringByReplacingCharactersInRange(range, withString: string)
if newText.length > 0 {
nextButton.enabled = true
} else {
nextButton.enabled = false
}
return true
}
How do I get this to work, because it just completely ignores it even if it compiles without errors.
The used delegates method was wrong.
shouldChangeCharactersInRange is for UITextField not UITextView
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
Method for UITextView
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
Requires UITextViewDelegate reference in class line:
class MyViewController: UIViewController, UITextViewDelegate {
}
AND it also requires a referencing outlet from the view controller to the textView delegate. Select the view controller, click on outlets, drag from referencing outlet to the textView, click delegate.
Probably you have not set the viewController as the delegate of the textField.
There are 2 ways to do that ...
1) Override viewDidLoad and mention textField.delegate = self
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
2) open the corresponding storyBoard, control drag the textField to the viewController and select delegate from the pop-up.
You have to define the function name with the correct name, otherwise it will not be recognised and not triggered
func textView(textView: UITextView, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
You'll have to include the UITextViewDelegate reference in the class definition, so that the deligate it assigned to the class:
class ViewController: UIViewController, UITextViewDelegate {
And you have to link the textView delegate (eg. in the viewDidLoad):
textView.delegate = self