I have a button that is disabled in my view controller. I have IBActions for when two text fields are edited. I am trying to enable the button when two text fields both contain integers. I have tried to do this, but whenever I run the ios simulator, the button stays disabled even when I put integers into each text field. Why is it staying disabled? I am new to swift, so please help me out. Here is the code for my entire project:
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
}
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
}
#IBAction func yourWeightEditingDidEnd(sender: AnyObject) {
yourWeightTextField.resignFirstResponder()
}
#IBAction func calorieNumberEditingDidEnd(sender: AnyObject) {
calorieNumberTextField.resignFirstResponder()
}
var yourWeightFilled = false
var calorieNumberFilled = false
func yourWeightTextFieldValueValidInt(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (yourWeightTextField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if let intVal = text.toInt() {
self.yourWeightFilled = true
} else {
self.yourWeightFilled = false
}
return true
}
func calorieNumberTextFieldValueValidInt(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (calorieNumberTextField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if let intVal = text.toInt() {
self.calorieNumberFilled = true
} else {
self.calorieNumberFilled = false
}
return true
}
#IBAction func yourWeightTextFieldEdited(sender: AnyObject) {
if self.yourWeightFilled && self.calorieNumberFilled {
self.calculateButton.enabled = true
}
}
#IBAction func calorieNumberTextFieldEdited(sender: AnyObject) {
if self.yourWeightFilled && self.calorieNumberFilled {
self.calculateButton.enabled = true
}
}
}
Your delegate methods are a bit mixed up -- they have to be named exactly what the caller expects, or they won't be found, so yourWeightTextFieldValueValidInt() and calorieNumberTextFieldValueValidInt() aren't being called at all. Instead you'll need to handle the edits to both text fields in a single method:
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 textField == yourWeightTextField {
yourWeightFilled = text.toInt() != nil
} else if textField == calorieNumberTextField {
calorieNumberFilled = text.toInt() != nil
}
return true
}
Related
[if all textfield is fill it will easily come back but if all textfield is empty and i click on last textfield then i want to come back to the previous textfield and so on how i achieved this please help me ]
import UIKit
class OTPVC: CommonViewController,UITextFieldDelegate {
#IBOutlet weak var aboutOtp: UIView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var bottomConstraint: NSLayoutConstraint!
#IBOutlet weak var firstOtptxt: UITextField!
#IBOutlet weak var secondOtptxt: UITextField!
#IBOutlet weak var thirdOtptxt: UITextField!
#IBOutlet weak var fourthOtptxt: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
setUpView()
firstOtptxt.delegate = self
secondOtptxt.delegate = self
thirdOtptxt.delegate = self
fourthOtptxt.delegate = self
}
private func setUpView() {
aboutOtp.makeCornerRadius(10)
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if ((textField.text?.count)!) < 1 && (string.count > 0) {
if textField == firstOtptxt{
secondOtptxt.becomeFirstResponder()
}
if textField == secondOtptxt {
thirdOtptxt.becomeFirstResponder()
}
if textField == thirdOtptxt {
fourthOtptxt.becomeFirstResponder()
}
if textField == fourthOtptxt {
fourthOtptxt.becomeFirstResponder()
}
textField.text = string
return false
} else if (((textField.text?.count)!) >= 1) && (string.count == 0) {
if textField == secondOtptxt {
firstOtptxt.becomeFirstResponder()
}
if textField == thirdOtptxt {
secondOtptxt.becomeFirstResponder()
}
if textField == fourthOtptxt {
thirdOtptxt.becomeFirstResponder()
}
if textField == firstOtptxt {
firstOtptxt.becomeFirstResponder()
}
textField.text = string
return false
}
else if ((textField.text?.count)!) >= 1 {
textField.text = string
return false
}
return true
}
}
[if all textfield is fill it will easily come back but if all textfield is empty and i click on last textfield then i want to come back to the previous textfield and so on how i achieved this please help me ]
[if all textfield is fill it will easily come back but if all textfield is empty and i click on last textfield then i want to come back to the previous textfield and so on how i achieved this please help me ]
protocol MyTextFieldDelegate: UITextFieldDelegate {
func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool)
}
class MyTextField: UITextField {
override func deleteBackward() {
// see if text was empty
let wasEmpty = text == nil || text! == ""
// then perform normal behavior
super.deleteBackward()
// now, notify delegate (if existent)
(delegate as? MyTextFieldDelegate)?.textField(self, didDeleteBackwardAnd: wasEmpty)
}
}
[just put a delegate method and its work fine in my project yippy]
there is a trick, you can have a 'space' in your textfields, so that problem will be solved .
I'm testing the my add button in the view controller file. It should go to validateName function in my model file and which returns true and then enables my addButton. But when I click on "Add" it doesn't change the text of the UITextView.
In viewcontroller.swift:
import UIKit
class ViewController: UIViewController,UITextFieldDelegate{
#IBOutlet weak var nameInputText: UITextField!
#IBOutlet weak var usernameInputText: UITextField!
#IBOutlet weak var passwordInputText: UITextField!
#IBOutlet weak var phoneInputText: UITextField!
#IBOutlet weak var emailInputText: UITextField!
#IBOutlet weak var addButton: UIButton!
#IBOutlet weak var textviewText: UITextView!
let model = Model()
#IBAction func addButton(_ sender: UIButton) {
textviewText.text = "hi"
}
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String)
-> Bool
{
addButton.isEnabled = false
let text: String = nameInputText.text!
var test_name: Bool
var name_array = [String]()
test_name = model.validateName(nametext: text)
if test_name == true{
addButton.isEnabled = true
name_array.append(text)
return true
}
return (true)
}
override func viewDidLoad() {
super.viewDidLoad()
usernameInputText.delegate = self
nameInputText.delegate = self
passwordInputText.isSecureTextEntry = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool{
usernameInputText.resignFirstResponder()
nameInputText.resignFirstResponder()
return (true)
}
}
//In model.swift:
import Foundation
class Model {
func validateName(nametext: String) -> Bool{
return true
}
}
I'm trying to implement UITextFieldDelegate in separate class, but it didn't working:
class ViewController: UIViewController {
#IBOutlet var TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let restrictor = TextFieldRestrictController()
TextField.delegate = restrictor
}
}
class TextFieldRestrictController : NSObject, UITextFieldDelegate {
public func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let inverseSet = NSCharacterSet(
charactersIn:"0123456789.").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator:"")
return string == filtered
}
}
But this is working:
class ViewController: UIViewController {
#IBOutlet var TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
TextField.delegate = self
}
public func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let inverseSet = NSCharacterSet(
charactersIn:"0123456789.").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator:"")
return string == filtered
}
}
Is there something wrong?
UITextField's .delegate is a weak property so at the end of viewDidLoad method,
restrictor will be deallocated because there is no other strong reference around that is pointing to the object which it points to.
You can try printing out ValidationTextField.delegate in viewDidAppear(animated:) and see it returns nil.
To overcome this problem, you can define restrictor as an instance variable so it'll stay alive as long as the view controller is alive:
class ViewController: UIViewController {
#IBOutlet weak var ValidationTextField: UITextField!
let restrictor = TextFieldRestrictController()
override func viewDidLoad() {
super.viewDidLoad()
ValidationTextField.delegate = restrictor
}
}
According to everything I've read here, I should override touchesBegan() to dismiss the keyboard (in my case DatePicker). Unfortunately touching the screen does not dismiss the DatePicker. Touching other UI elements like the UISteppers dismisses the keyboard just fine, and it is using the same function of CloseKeyboard()
class RecordWorkoutTableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var dateTextField: UITextField!
#IBOutlet weak var weightLabel: UILabel!
#IBOutlet weak var setOneLabel: UILabel!
#IBOutlet weak var setTwoLabel: UILabel!
#IBOutlet weak var weightStepper: UIStepper!
#IBOutlet weak var setOneStepper: UIStepper!
#IBOutlet weak var setTwoStepper: UIStepper!
var newDate: NSDate? {
didSet {
dateTextField.text = NSDateToPrettyString(newDate!)
}
}
var newWeight: Int? {
didSet {
weightLabel.text = "\(newWeight!) lbs"
}
}
var newSetOne: Int? {
didSet {
setOneLabel.text = "Set 1: \(newSetOne!) reps"
}
}
var newSetTwo: Int? {
didSet {
setTwoLabel.text = "Set 2: \(newSetTwo!) reps"
}
}
var workout: Workout?
// MARK: UITextFieldDelegate
func textFieldDidBeginEditing(textField: UITextField) {
let datePicker = UIDatePicker()
textField.inputView = datePicker
datePicker.addTarget(self, action: #selector(RecordWorkoutTableViewController.datePickerChanged(_:)), forControlEvents: .ValueChanged)
}
func datePickerChanged(sender: UIDatePicker) {
newDate = sender.date
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// disable editing of date text. datepicker input only
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return false
}
// MARK: Helper Functions
func closeKeyboard() {
self.view.endEditing(true)
}
// MARK: Touch Events
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
closeKeyboard()
}
override func viewDidLoad() {
super.viewDidLoad()
dateTextField.delegate = self
newDate = NSDate()
if let lastWorkout = workout {
newWeight = lastWorkout.sets[0].weight
newSetOne = lastWorkout.sets[0].repCount
newSetTwo = lastWorkout.sets[1].repCount
} else {
newWeight = 0
newSetOne = 9
newSetTwo = 8
}
weightStepper.stepValue = 5
weightStepper.maximumValue = 995
weightStepper.value = Double(newWeight!)
setOneStepper.stepValue = 1
setOneStepper.maximumValue = 20
setOneStepper.value = Double(newSetOne!)
setTwoStepper.stepValue = 1
setTwoStepper.maximumValue = 20
setTwoStepper.value = Double(newSetTwo!)
}
#IBAction func weightStepperChanged(sender: UIStepper) {
newWeight = Int(sender.value)
closeKeyboard()
}
#IBAction func setOneStepperChanged(sender: UIStepper) {
newSetOne = Int(sender.value)
closeKeyboard()
}
#IBAction func setTwoStepperChanged(sender: UIStepper) {
newSetTwo = Int(sender.value)
closeKeyboard()
}
}
You said in the comments that you have another class in your app named Set. Since this class is in the same module as your table view controller, Swift is prioritizing it over it's built in class.
You can fix this by either renaming your Set class, or explicitly specifying the Swift module in the function declaration:
override func touchesBegan(touches: Swift.Set<UITouch>, withEvent event: UIEvent?) {
closeKeyboard()
}
I'm developing note app, when the text view is empty the done button should be disabled so user could not be able to save empty notes into data base, else the button should be enabled.
here's my code below, my attempts have failed; how I can solve this problem?
#IBOutlet weak var textView: UITextView!
#IBOutlet weak var done: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
title = note?.text
if (self.textView.text.isEmpty){
done.enabled = false
}
if let noteContent = note
{
textView.text = noteContent.text
}
self.navigationController!.toolbarHidden = false;
}
func textViewShouldBeginEditing(textView: UITextView) -> Bool{
done.enabled = true
return done.enabled
}
Make your view controller conform to UITextViewDelegate protocol
In Interface Builder, connect the delegate on the text view to your view controller.
Add the following function to your view controller:
func textViewDidChange(textView: UITextView) {
if textView == self.textView {
self.doneButton.enabled = !textView.text.isEmpty
}
}
Try to use another delegate method for you're purpose. This is example :
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
if (textView.text.isEmpty) {
button.enabled = false
}
}
}
extension ViewController: UITextViewDelegate {
func textView(textView: UITextView, range: NSRange, replacementText text: String) -> Bool
{
if (!textView.text.isEmpty) {
button.enabled = true
} else {
button.enabled = false
}
return true
}
}
Try this in textViewDidChange method:
yourBarButtonItem.isEnabled = !(yourTextField.text?.isEmpty ?? false)