Swift: Value Changing Control Events Not Calling? - ios

So I have added targets to my IBActions I have created that occur when the value of a text field changes. When these actions occur, the system should check if the two text fields are both integers. I have set two variables set to false, and they are set to true when both of them are an int. In the IBActions, I have if statements that tell a button to be enabled if both of the variables contain integers. When I run the simulator, this button doesn't enable when both of the text fields contain an integer.
I am new to swift, so if possible, please write all of the code out and where it should be in my code. Here is what I have so far:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var calculatorButton: UIButton!
#IBOutlet weak var inspirationLabel: UILabel!
#IBOutlet weak var beginningLabel: UILabel!
#IBOutlet weak var calculatorContainer: UIView!
#IBOutlet weak var answer1Label: UILabel!
#IBOutlet weak var doneButton: UIButton!
#IBOutlet weak var yourWeightTextField: UITextField!
#IBOutlet weak var calorieNumberTextField: UITextField!
#IBOutlet weak var menuExampleButton: UIButton!
#IBOutlet weak var aboutButton: UIButton!
#IBOutlet weak var calculateButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib
yourWeightTextField.delegate = self
calorieNumberTextField.delegate = self
calculateButton.enabled = false
// Calling the textfield valueChanged Methods
yourWeightTextField.addTarget(self, action:"yourWeightValueChanged:", forControlEvents:.ValueChanged);
calorieNumberTextField.addTarget(self, action:"calorieNumberValueChanged:", forControlEvents:.ValueChanged);
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func calculatorButtonTapped(sender: AnyObject) {
calculatorContainer.hidden = false
inspirationLabel.hidden = true
beginningLabel.hidden = true
menuExampleButton.hidden = true
aboutButton.hidden = true
}
var yourWeightFilled = false
var calorieNumberFilled = false
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
// If the textfields have the properties of the function
if textField == yourWeightTextField {
yourWeightFilled = text.toInt() != nil
} else if textField == calorieNumberTextField {
calorieNumberFilled = text.toInt() != nil
}
return true
}
func textFieldShouldReturn(textField: UITextField) -> Bool
{
textField.resignFirstResponder();
return true;
}
// The methods to close the keyboard when editing is finished
#IBAction func yourWeightEditingDidEnd(sender: AnyObject) {
yourWeightTextField.resignFirstResponder()
}
#IBAction func calorieNumberEditingDidEnd(sender: AnyObject) {
calorieNumberTextField.resignFirstResponder()
}
#IBAction func yourWeightValueChanged(sender: AnyObject) {
// If both variables are true and the text fields contain integers, enable button
if self.yourWeightFilled && self.calorieNumberFilled {
self.calculateButton.enabled = true
}
}
#IBAction func calorieNumberValueChanged(sender: AnyObject) {
// If both variables are true and the text fields contain integers, enable button
if self.yourWeightFilled && self.calorieNumberFilled {
self.calculateButton.enabled = true
}
}
}

You should look for EditingChaged event, not ValueChanged
EDIT:
What I mean is to change from:
yourWeightTextField.addTarget(self, action:"yourWeightValueChanged:", forControlEvents:.ValueChanged);
calorieNumberTextField.addTarget(self, action:"calorieNumberValueChanged:", forControlEvents:.ValueChanged);
to :
yourWeightTextField.addTarget(self, action:"yourWeightValueChanged:", forControlEvents:.EditingChanged);
calorieNumberTextField.addTarget(self, action:"calorieNumberValueChanged:", forControlEvents:.EditingChanged);
You simply are looking for wrong event.

If you are looking for a text changed event , then Right Click on the text field select Editing Did End from the Sent Events . You can see a circle on the right end click the circle Hold Down Ctrl and Drag it to your ViewController file. Name the Action you want and . I have provided some screen shots for this.
Here i name the Action TextChanged
I am Using Xcode 7 Swift 2 here
Right Click on the Text Box and You can see Something Like this
Finally You can see the TextChanged event Created. when you type something on a text box and click return this event fires.

Related

Best way to dismiss keyboard when tapping outside of UITextField - IOS

I've found a few threads here about this, and some videos online about it as well, but every solution seems to have problems reported by others. The simplest solution I've found is the one below.
import UIKit
class SignupController: UIViewController, UITextFieldDelegate {
// Outlets
#IBOutlet weak var logoImage: UIImageView!
#IBOutlet weak var nameTF: CustomTextField!
#IBOutlet weak var emailTF: CustomTextField!
#IBOutlet weak var passwordTF: CustomTextField!
#IBOutlet weak var confirmPassTF: CustomTextField!
// Actions
#IBAction func signupButton(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
logoImage.image = UIImage(named: "logo2")
nameTF.delegate = self
emailTF.delegate = self
passwordTF.delegate = self
confirmPassTF.delegate = self
}
// Moves to next text field each time return key is pressed
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == nameTF {
textField.resignFirstResponder()
emailTF.becomeFirstResponder()
} else if textField == emailTF {
textField.resignFirstResponder()
passwordTF.becomeFirstResponder()
} else if textField == passwordTF {
textField.resignFirstResponder()
confirmPassTF.becomeFirstResponder()
}else if textField == confirmPassTF {
textField.resignFirstResponder()
}
return true
}
// Dismisses keyboard when tapped
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
}
It works, is very simple, but my project and coding experience are in their infancy, so I'm not sure if this is the best method simply because it's short, or if there's something I'm missing due to lack of experience/knowledge?
Anybody know of a better solution, or is this one just fine?
just do this:
class viewController: UIViewController, UITextFieldDelegate {
// Outlets
#IBOutlet weak var logoImage: UIImageView!
#IBOutlet weak var nameTF: CustomTextField!
#IBOutlet weak var emailTF: CustomTextField!
#IBOutlet weak var passwordTF: CustomTextField!
#IBOutlet weak var confirmPassTF: CustomTextField!
// Actions
#IBAction func signupButton(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
logoImage.image = UIImage(named: "logo2")
nameTF.delegate = self
emailTF.delegate = self
passwordTF.delegate = self
confirmPassTF.delegate = self
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dissMissKeyboard))
view.addGestureRecognizer(tap)
}
func dissMissKeyboard() {
view.endEditing(true)
}
I prefer to use UITextField delegate method:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
view.endEditing(true)
return true
}
or setup inputAccessoryView which have 'done' or 'exit' button.
Then you need to implement the gesture recognition for this . Or you can do like this :
override func viewDidLoad() {
super.viewDidLoad()
//Looks for single or multiple taps.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dissMissKeyboard))
//Uncomment the line below if you want the tap not not interfere and cancel other interactions.
//tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
//Calls this function when the tap is recognized.
func dissMissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}

How To Prompt a New Page After Inserting Name?

I created a simple page of my app today. And, now I want to expand it.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
#IBOutlet weak var myTextField: UITextField!
#IBOutlet weak var display: UILabel!
#IBAction func myButtonPressed(_ sender: Any) {
display.text = "Hi \(myTextField.text!)! What can I do for you
today?"
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
I want the app to prompt a new page after the user entered their name.
You can conform to the UITextViewDelegate and present a viewController in func textViewDidEndEditing(_ textView: UITextView) like:
extension ViewController: UITextFieldDelegate {
func textViewDidEndEditing(_ textView: UITextView) {
self.present(/*the targeted view controller*/)
}
}
You can add target like
// In viewDidLoad
myTextField.addTarget(self, action: #selector(onNameChange(sender:)), for: .editingChanged)
// on value change
#objc func onNameChange(sender:UITextField) {
// Do something
}
So far I got your query as:
You want to go to new ViewController when the user is done with filling his name in the textfield.
If I got you right then choose the "GO" (or any thing you wish from options) as the Return Key value inside 'Text Input Traits Section' of Attribute Inspector.
And now add this code in your view controller class with implementing UITextFieldDelegate:
func textFieldShouldReturn(_ textField: UITextField) -> Bool // called when 'return' key pressed. return false to ignore.
{
print(textField.tag)
if (textField.text?.isEmpty)! {
//show alert that text field is empty
return false
}
/* as per your case we have only one textfield,
So there no need of switch case and you can
directly present your next vc from here without having any button on UI */
return false
}

Change the text of a label with a button in iOS

Firstly, let me say I'm new to Swift and Xcode. I have a label that displays some text and I want that text to change when a button is pressed.
Here is the code in the UIViewController:
var txt = "Hey"
#IBOutlet weak var Text: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
showText()
}
func showText(){
Text.text = txt
}
#IBAction func Button(_ sender: Any) {
txt = "Hello"
}
The buttons and labels are correctly linked to their main.storyboard counterparts. When I run this and press the button the text doesn't change.
viewDidLoad() is only called one time when the ViewController is created. showText() needs to be called after txt is set if you want to display it. One way to automate this is to add a property observer to txt to call showText() when txt is updated:
var txt = "Hey" {
didSet {
showText()
}
}
I will add that it is more flexible and perhaps elegant to have your showText() method take the actual text to show as an argument, instead of depending on some internal state (the value of the property txt: String, that isn't immediately evident at the call site) to accomplish its task:
#IBOutlet weak var textLabel: UILabel!
func showText(_ text: String){
self.textLabelabel?.text = text
// (optional chaining to avoid crash if accidentally
// called before viewDidLoad())
}
#IBAction func buttonAction(_ sender: Any) {
self.showText("Hello") // From here it is clear what text will be shown
}
change your code as per below
var txt = "Hey"
#IBOutlet weak var Text: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
showText()
}
func showText(){
Text.text = txt
}
#IBAction func Button(_ sender: UIButton) {
txt = "Hello"
showText()
}
Change Text of label with button just need to pass the text in label;
//Outlets
#IBOutlet weak var firstLabel: UILabel!
#IBOutlet weak var secondLabel: UILabel!
//Button Action
#IBAction func textChabge(_ sender: Any) {
firstLabel.text = "newText"
secondLabel.text = "newText"
}
just change your IBAction like this.
#IBAction func Button(_ sender: Any) {
txt = "Hello"
showText()
}

iOS: How to get the current visible keyboard type?

How do I find out if the keyboard is of type numeric, Twitter, email, etc...?
edit: Is there a way to detect keyboard type without using an outlet?
Consider that you have tow textFields in the ViewController, You will need to implement textFieldShouldBeginEditing method from UITextFieldDelegate protocol, as follows:
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tfEmail: UITextField!
#IBOutlet weak var tfPassword: UITextField!
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField.keyboardType == .emailAddress {
// this is the tfEmail!
}
if textField.isSecureTextEntry {
// this is tfPassword!
}
}
}
Make sure their delegates are connected to the ViewController, programmatically:
tfEmail.delegate = self
tfPassword.delegate = self
or from the Interface Builder.
Note that you can recognize the keyboard type for the current textField by checking its keyboardType property, which is an instance of UIKeyboardType enum:
The type of keyboard to display for a given text-based view. Used with
the keyboardType property.
What about UITextView?
The same exact functionality should be applied when working with UITextViews, but you need to implement textViewDidBeginEditing(_:) method from UITextViewDelegate protocol instead of implementing textFieldShouldBeginEditing. Again, make sure the delegate of the textView is connected to the ViewController.
Also,
If your main purpose of checking the keyboard type is just for recognizing what is the current responded textField/textView, I suggest to do a direct check:
class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {
#IBOutlet weak var tfEmail: UITextField!
#IBOutlet weak var tfPassword: UITextField!
#IBOutlet weak var textViewDescription: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
tfEmail.delegate = self
tfPassword.delegate = self
textViewDescription.delegate = self
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField === tfEmail {
// this is the tfEmail!
}
if textField === tfPassword {
// this is tfPassword!
}
}
func textViewDidBeginEditing(_ textView: UITextView) {
if textView === textViewDescription {
// this is description textview
}
}
}
For more information about === operator you might want to check this question/answers.
Hope this helped.
In addition to Ahmad F 's great answer, this is my approach of getting the current keyboard type, at any time:
Step 1: Delegate UITextField
class File: UIViewController, UITextFieldDelegate{//...}
Update viewDidLoad() to this:
#IBOutlet weak var normalTextField: UITextField!
#IBOutlet weak var numberTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
numberTextField.keyboardType = .numberPad
normalTextField.keyboardType = .default
emailTextField.keyboardType = .emailAddress
numberTextField.delegate = self
normalTextField.delegate = self
emailTextField.delegate = self
}
Step 2: Working with UITextField's methods:
Add a variable called keyboardType, as below:
var keyboardType: UIKeyboardType? = nil
Then, change it whenever a new textField begins editing:
func textFieldDidBeginEditing(_ textField: UITextField) {
keyboardType = textField.keyboardType
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
keyboardType = nil
return true
}
Step 3: Create and call a function like below:
func getCurrentKeyboard() -> String{
if keyboardType == nil{
return "no current keyboard"
}
else if keyboardType == .numberPad{
return "number"
}
else if keyboardType == .emailAddress{
return "email"
}
else{
return "default"
}
}
#IBAction func displayCurrentKeyboard(_ sender: UIButton) {
print(self.getCurrentKeyboard())
}
And this outputs: email / number / no current keyboard / default, depending on the case.
If you want to check which type of keyboard it is with if-else statements, you can change your displayCurrentKeyboard() method to this:
#IBAction func displayCurrentKeyboard(_ sender: UIButton) {
let keyboardString = self.getCurrentKeyboard()
if keyboardString == "number"{
//...
}
else if keyboardString == "email"{
//...
}
else{
//...
}
}
And that's it! You can call this wherever you want in your code with this usage:
let keyboardString = self.getCurrentKeyboard()
NOTE: This method also handles the case of no keyboard visible on the screen, returning no current keyboard, in this case.
Let me know if this helps!

textFieldShouldBeginEditing is not firing for the correct textfield in Swift 1.2

I am not sure why textFieldShouldBeginEditing returns all of the UiTextField
File: PaymentViewControllerDummy.swift
class PaymentViewControllerDummy: UIViewController, UITextFieldDelegate {
#IBOutlet weak var dobTextField: UITextField!
#IBOutlet weak var nameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
dobTextField.tag = 1
nameTextField.tag = 2
dobTextField.delegate = self
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
println("Tage From textFile: \(textField.tag) ")
println("Tage From dobTextField: \(dobTextField.tag) ")
if(textField.tag == dobTextField.tag) {
println("You are editing date of birth")
return false
} else {
return true
}
}
}
All the IBOutlets are connected. This is very standard code. I have done this times after time however whichever textfield I press textField == self.dobTextField comes back true
Console result:
Am I missing something?
Edit
Here is the Interface builder screens
NOTE
I made a standalone project and copy the codes to the project and it worked as it should however it is not working in this project. Could it be something in the StoryBoard ?
You shouldn't check UI objects with equality comparison.
You had better use tags (or maybe labels, not preferred however) in order to conduct protocol calls over different UI objects.
class PaymentViewControllerDummy: UIViewController, UITextFieldDelegate {
#IBOutlet weak var dobTextField: UITextField!
#IBOutlet weak var nameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
dobTextField.delegate = self
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
println(textField.tag)
println(dobTextField.tag)
if(textField.tag == dobTextField.tag) {
println("You are editing date of birth")
return false
} else {
return true
}
}
}
Also you DON'T have to refer self if you want to access instance variables, if you are not in a block (closure).
The best thing to access text fields in text field did editing method is via tags. Set the tag of both the text fields let say self.dobTextField.tag=1 & self.nameTextField.tag=2. Then in
func textFieldShouldBeginEditing(textField: UITextField) -> Bool
println(textField.tag)
println(dobTextField.tag)
if(textField.tag == 1) //dob text field is currently in edit mode
{
println("You are editing date of birth")
return true
}
else // name text field is in edit mode
{
return true
}
}

Resources