0

This is my first question in this forum. I would like to know how to enable a UIBarButtonItem only if a UITextField has text in it. I have seen many examples of how to do this in Swift 2 but not Swift 3. This is for a simple app to save some data to core data. I do not have any code to show other then the UIOutlets etc as I am unsure how to check the UITextField for text on the fly.

3 Answers3

0

You need to check length of textField.

//MARK: - UITextFieldDelegate

func textFieldDidEndEditing(_ textField: UITextField) {

    if let text = exampleTextFiled.text {
        exampleBarButtonItem.isEnabled = text.characters.count > 0
    }
}

At the top of you controller you need to add UITextFieldDelegate

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var exampleTextField: UITextField!
    @IBOutlet var exampleBarButtonItem: UIBarButtonItem!

    // Your code 
}

And in the storyboard you can ctrl-drag from textField to controller to add delegate.

P. Pawluś
  • 298
  • 6
  • 17
  • @ P.Pawlus So after looking at three answers I have found a solution. I followed your code but I couldn't get it to work but I might not be understanding your solution fully. What I did was added an @IBAction action from the Text Field in the Scene to the controller for the action Editing Changed and used your above to enable or disable the BarButton. – Terry Ladden Oct 18 '16 at 12:48
  • @TerryLadden Don't add @IBAction to textField, you need to add just @IBOutlet and delegate. You can do this by ctrl-dragging from text field to `View Contrller` (yellow circle above your controller in storyboard). You need to chose your name of @IBOutlet and delegate. If you don't now how to do this it should help: https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson3.html - Part: Create Outlets for UI Elements – P. Pawluś Oct 18 '16 at 13:03
  • I have read the documentation and understand how all this works a lot better. Thank you. I love this learning process. However while your solution will work once I have finished entering text into the text field what I would like to do is validate that there is text in the textfield while I am typing and have the save button enabled only when there is text in the text field as I type. Like I posted in my answer I can do that using an IBOutlet but I cannot seem to figure out how to do it using the textfield as a delegate. Any suggestions? – Terry Ladden Oct 20 '16 at 12:00
0

That's why I don't recommend using Interface Builder and Storyboards, the developer gets "dumbed down".

Anyhow, the algorithm is something like this:

1) Text fields have callback methods or "delegate" methods for text field events like user tapping on the return/done key.

So firstly, you need to tell your text field the delegate is your view controller.

2) You define the necessary UITextField delegate methods (https://developer.apple.com/reference/uikit/uitextfielddelegate)

3) There is a hasText method (newly available for iOS 10+) for UITextField to tell if your text field has any text. If there is, enable the bar button item, otherwise disable it.

You could alternatively use if let optional binding to unwrap your textField.text? property, then check the text.characters.count is greater than 0 like so:

if let text = textField.text {
    navigationItem.rightBarButtonItem?.isEnabled = text.characters.count > 0
}

This is the conventional way of doing it (before iOS 10 if you want to support older iOS version) :D

The code in full is below:

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet var myTextField:UITextField!

    ...

    override func viewDidLoad() {
        super.viewDidLoad()

        // self is referring to this view controller
        ...
        myTextField.returnKeyType = UIReturnKeyType.done
        myTextField.delegate = self
    }

    // UITextField Delegate Methods
    func textFieldDidEndEditing(_ textField: UITextField) {

        // get the navigation bar button (right bar button in my case)
        // and set its "isEnabled" property depending on whether
        // the textField has any text using "hasText" of UITextField
        navigationItem.rightBarButtonItem?.isEnabled = textField.hasText
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {

        hideKeybaord()

        return false
    }

    // UITouches delegate methods for extra user experience polish
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        // hides keyboard when user taps on the background
        hideKeybaord()
    }

    // resusable hideKeyboard method
    func hideKeybaord() {
        myTextField.resignFirstResponder()

        // in case you need to hide all other text fields in the future
        // textField2.resignFirstResponder()
        // textField3.resignFirstResponder()
    }
}
Zhang
  • 11,549
  • 7
  • 57
  • 87
  • Thanks for the answer and code, at the moment I am just using the Hardware keyboard to enter text so I will be looking at your code to work with the iOS keyboard – Terry Ladden Oct 18 '16 at 12:58
  • Hardware keyboard? Are you building some sort of app that make use of 3rd party keyboards from Logitech for example? – Zhang Oct 18 '16 at 16:16
  • No, not building app to make use of 3rd party keyboard. I am learning Swift and I am just making a simple app to learn core data etc.. I am using the simulator hardware keyboard to input text. Next I will consider using the onscreen keyboard. – Terry Ladden Oct 18 '16 at 20:47
0

Below is the code I implemented to resolve my problem. It does not take into consideration the iOS keyboard. The last function is the @IBAction (Editing Changed) added to the controller (ViewController.swift) from the TextField in the Scene. I right clicked the TextField in the scene selected the Action, Editing Changed and dragged it to the View Controller. Thanks to all for your iuput and code!!

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

   // Add Outlet
   @IBOutlet weak var tvShowName: UITextField!
   @IBOutlet weak var saveButton: UIBarButtonItem!


   // Add functions

   @IBAction private func saveButton(_ sender: UIBarButtonItem) {

      let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
      let newTVShow = TVShows(context: context)

      newTVShow.name = tvShowName.text

      do {
         try context.save()
         navigationController!.popViewController(animated: true)
      } catch {
         let alert = UIAlertController(title: "Oops!", message: "Failed to save the TV Show", preferredStyle: UIAlertControllerStyle.alert)
         alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
         self.present(alert, animated: true, completion: nil)
      }
   }

   @IBAction private func cancelButton(_ sender: UIBarButtonItem) {
      // Code for cancel
      navigationController!.popViewController(animated: true)
   }

   override func viewDidLoad() {
      super.viewDidLoad()
      saveButton.isEnabled = false
   } 

   @IBAction func tvShowTextFieldEditChanged(_ sender: UITextField) {
      if let text = tvShowName.text{
          saveButton.isEnabled = text.characters.count > 0
      }
   }
}
P. Pawluś
  • 298
  • 6
  • 17