I'm very new to all of this and I found some code that got me understanding some of this syntax. I'm trying to create a textfield that lets me type in a value that updates the stepper's value. The stepper currently works (updates the uitextfield) but when I change the value in the textfield it doesn't update the stepper's value, so when I click on the stepper, it reverts back to whatever value it was before I typed in a value... Can anyone tell me why the two functions STracksValueDidChange and CTrackValueDidChange have errors?
Here's my code so far:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var STracks: UITextField!
#IBOutlet weak var STracksStepper: UIStepper!
#IBOutlet weak var CTracks: UITextField!
#IBOutlet weak var CTrackStepper: UIStepper!
override func viewDidLoad() {
super.viewDidLoad()
STracksStepper.autorepeat = true
STracksStepper.maximumValue = 100.0
STracksStepper.minimumValue = 2.0
STracksStepper.stepValue = 2.0
print(STracksStepper.value)
STracks.text = "\(Int(STracksStepper.value))"
STracksStepper.addTarget(self, action: "SstepperValueDidChange:", forControlEvents: .ValueChanged)
STracks.addTarget(self, action: "STextValueDidChange:", forControlEvents: .ValueChanged)
CTrackStepper.autorepeat = true
CTrackStepper.maximumValue = 100.0
CTrackStepper.minimumValue = 2.0
CTrackStepper.stepValue = 2.0
print(CTrackStepper.value)
CTracks.text = "\(Int(CTrackStepper.value))"
CTrackStepper.addTarget(self, action: "CstepperValueDidChange:", forControlEvents: .ValueChanged)
CTracks.addTarget(self, action: "CTextValueDidChange:", forControlEvents: .ValueChanged)
}
//Steppers will update UITextFields
func SstepperValueDidChange(stepper: UIStepper) {
let stepperMapping: [UIStepper: UITextField] = [STracksStepper: STracks]
stepperMapping[stepper]!.text = "\(Int(stepper.value))"
}
func STracksValueDidChange(SText: UITextField) {
let STextMapping: [UITextField: UIStepper] = [STracks: STracksStepper]
STextMapping[SText]!.value = "(SText.text)"
}
func CstepperValueDidChange(stepper: UIStepper) {
let stepperMapping: [UIStepper: UITextField] = [CTrackStepper: CTracks]
stepperMapping[stepper]!.text = "\(Int(stepper.value))"
}
func CTrackValueDidChange(CText: UITextField) {
let CTextMapping: [UITextField: UIStepper] = [CTracks: CTrackStepper]
CTextMapping[CText]!.value = "(CText.text)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Try something like this.
CTrackStepper.value = Double(Textfield.text)
I am not so sure what the mapping is in your code.
But i don't think you need it for changing the value.
Update, made a project my self:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textfield: UITextField!
#IBOutlet weak var stepper: UIStepper!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func stepperValueChanged(sender: UIStepper) {
textfield.text = String(sender.value)
}
#IBAction func valueChanged(sender: UITextField) {
if Double(sender.text!) != nil {
stepper.value = Double(sender.text!)!
}
}
}
For steppervaluechanged and valuechanged just drag from uistepper and textfield and choose action and change the Anyobject to Uistepper of Uitextfield.
Good luck :)
Related
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)
}
Hi i'm new with Swift programming.
What im trying to do is Disable my button (signIn) in viewDidLoad and only enable when the textfields have text in them. Here's what i've achieved so far. (not much though!)
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
signIn.isEnabled = false
// Do any additional setup after loading the view, typically from a nib.
}
#IBOutlet weak var emailtxt: UITextField!
#IBOutlet weak var passwordtxt: UITextField!
#IBOutlet weak var signIn: UIButton!
I need help to create a function in signIn that keeps button disabled until text fields (emailtxt & passwordtxt) have text in them and then proceed.
Glad if anyone can sort me.
Thanks in advance!
First add these for all of your textFields in viewDidLoad():
emailtxt.addTarget(self, action: #selector(textFieldDidChange(_:)),
for: UIControlEvents.editingChanged)
passwordtxt.addTarget(self, action: #selector(textFieldDidChange(_:)),
for: UIControlEvents.editingChanged)
Then use this:
#objc func textFieldDidChange(_ textField: UITextField) {
self.buttonIsEnabled()
}
func buttonIsEnabled() {
var buttonIsEnabled = true
defer {
self.signIn.isEnabled = buttonIsEnabled
}
guard let emailtxt = self.emailtxt.text, !emailtxt.isEmpty else {
addButtonIsEnabled = false
return
}
guard let passwordtxt = self. passwordtxt.text, ! passwordtxt.isEmpty else {
addButtonIsEnabled = false
return
}
}
I use this way in my codes and it works well.
Even you can add more methods for additional checking to buttonIsEnabled, like:
self.checkEmailIsValid(for: emailtxt)
Of course you should handle this method before:
func checkEmailIsValid(for: String) {
//...
}
Set ViewController as delegate for emailtxt and passwordtxt like this,
override func viewDidLoad() {
super.viewDidLoad()
signIn.isEnabled = false
emailtxt.delegate = self
passwordtxt.delegate = self
// Do any additional setup after loading the view, typically from a nib.
}
Conform your ViewController to UITextFieldDelegate and enable/disable as the text input is finished,
extension ViewController: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
if emailtxt.text?.isEmpty == false && passwordtxt.text?.isEmpty == false {
signIn.isEnabled = true
} else {
signIn.isEnabled = false
}
}
}
Here is the fix for your code you shared.
import UIKit
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
extension SignInVC: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
if emailtxt.text?.isEmpty == false && passwordtxt.text?.isEmpty == false {
signIn.isEnabled = true
} else {
signIn.isEnabled = false
}
}
}
class SignInVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
signIn.isEnabled = false
emailtxt.delegate = self
passwordtxt.delegate = self
self.hideKeyboardWhenTappedAround()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var emailtxt: UITextField!
#IBOutlet weak var passwordtxt: UITextField!
#IBOutlet weak var signIn: UIButton!
}
What I would do is create an IBAction from one of your text fields, and set the event to Editing Changed:
The code should look like this:
#IBAction func textFieldEditingDidChange(_ sender: UITextField) {
}
You can then connect that same outlet to both of your text fields by dragging from the outlet to your remaining field. If you've connected both correctly, clicking on the circle to the left of your IBAction should show two text fields:
The action will now be fired every time text changes in either of your fields.
Then, at the top of the file, I'd create a computed property that returns false unless there is something in both fields:
var shouldEnableButton: Bool {
guard let text1 = textField1.text, let text2 = textField2.text else {
return false
}
return text1.isEmpty && text2.isEmpty ? false : true
}
Finally, we add shouldEnableButton to our IBAction:
#IBAction func textFieldEditingDidChange(_ sender: UITextField) {
button.isEnabled = shouldEnableButton
}
Important
When you connect your second text field to the outlet, it will incorrectly assign Editing Did End as its event:
Delete this event and click and drag from Editing Changed to your IBAction:
Use SwiftValidator
https://github.com/SwiftValidatorCommunity/SwiftValidator
by this, you will set validation of email & password like below
import SwiftValidator
let validator = Validator()
validator.registerField(emailTextField, errorLabel: emailErrorLabel, rules: [RequiredRule(), EmailRule(message: "Invalid email")])
// MARK: - ValidationDelegate
extension ViewController: ValidationDelegate {
func validationSuccessful() {
self.loginUser()
}
func validationFailed(_ errors:[(Validatable ,ValidationError)]) {
for (field, error) in errors {
//Handle as per need - show extra label - shake view etc
/*
if let field = field as? UITextField {
Utilities.shakeTheView(shakeView: field)
}
error.errorLabel?.text = error.errorMessage
error.errorLabel?.isHidden = false
*/
}
}
}
I want to create a simple BMI calculator using height and weight and I am having trouble converting my UITextField strings to integers for the calculation.
Here's my working code:
import UIKit
class BMICalculator: UIViewController {
//MARK: Properties
#IBOutlet weak var weightField: UITextField!
#IBOutlet weak var heightField: UITextField!
#IBOutlet weak var solutionTextField: UILabel!
#IBAction func calcButton(_ sender: AnyObject) {
let weightInt = Int(weightField)
let heightInt = Int(heightField)
solutionTextField.text = weightInt/(heightInt*heightInt)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Anyone have any ideas? I tried searching for the solution but couldn't find anything specific to this issue.
Use this:
guard let text1 = weightField.text else {
return
}
guard let text2 = heightField.text else {
return
}
guard let weightInt = Int(text1) else {
return
}
guard let heightInt = Int(text2) else {
return
}
solutionTextField.text = weightInt /(heightInt*heightInt)
//Change your name for this outlet 'solutionTextField' to 'solutionLabel' since it is a UILabel not UITextField
The TextField only accepts a String, it wont take an Int.
Change this:
solutionTextField.text = weightInt/(heightInt*heightInt)
To this:
solutionTextField.text = String(weightInt/(heightInt*heightInt))
I don't think your code is working. To get the values out of your UITextFields and convert them to Ints, you'll need to pull them out of the '.text properties. Then, when you calculate the result, you'll need to convert it back to a string and set solutionTextField?.text equal to that result.
class BMICalculator: UIViewController {
//MARK: Properties
#IBOutlet weak var weightField: UITextField!
#IBOutlet weak var heightField: UITextField!
#IBOutlet weak var solutionTextField: UILabel!
#IBAction func calcButton(_ sender: AnyObject) {
let weightInt = Int((weightField?.text!)!)
let heightInt = Int((heightField?.text!)!)
let solution = weightInt!/(heightInt!*heightInt!)
solutionTextField?.text = "\(solution)"
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Keep in mind that this code is very dangerous because you're not safely unwrapping optionals, but that's a different thread.
Hope this helps.
I have 3 sliders as shown above:
And when the "Min tip" it's equal or greater than "Default tip", I add 1 to "Default tip". And the same logic it's for Default to Max tip.
So, until now I have this code, that works partially because the Default tip's slider grows in the UI, but the label isn't updated because the delegate isn't called.
#IBOutlet weak var minLabel: UILabel!
#IBOutlet weak var defaultLabel: UILabel!
#IBOutlet weak var maxLabel: UILabel!
#IBOutlet weak var minSlider: UISlider!
#IBOutlet weak var defaultSlider: UISlider!
#IBOutlet weak var maxSlider: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
minSlider.addTarget(self, action: #selector(SettingsViewController.minSliderValueChanged(_:)), forControlEvents: UIControlEvents.AllEvents)
defaultSlider.addTarget(self, action: #selector(SettingsViewController.defaultSliderValueChanged(_:)), forControlEvents: UIControlEvents.AllEvents)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func minSliderValueChanged(sender: UISlider) {
let valueMin = Int(minSlider.value)
let valueDefault = Int(defaultSlider.value)
_ = Int(maxSlider.value)
minLabel.text = "Min tip: \(valueMin)%"
if(valueMin >= valueDefault){
defaultSlider.value = Float(valueMin+1)
}
}
#IBAction func defaultSliderValueChanged(sender: UISlider) {
let value = Int(defaultSlider.value)
defaultLabel.text = "Default tip: \(value)%"
}
#IBAction func maxSliderValueChanged(sender: UISlider) {
let value = Int(maxSlider.value)
maxLabel.text = "Max tip: \(value)%"
}
What I'm missing?
After defaultSlider.value = Float(valueMin+1) update the text of the label, like so:
defaultLabel.text = "Default tip: \(valueMin+1)%"
Slider values range from 0 (slider at left end) to 1 (slider at right end).
By doing let valueMin = Int(minSlider.value), variable valueMin can either be 0, or 1. I assume this isn't what you want really.
Perhaps this is closer to what you're looking for?
#IBAction func minSliderValueChanged(sender: UISlider) {
let valueMin = minSlider.value
let valueDefault = defaultSlider.value
_ = Int(maxSlider.value)
minLabel.text = "Min tip: \(Int(valueMin*100))%"
if(valueMin >= valueDefault){
defaultSlider.value = valueMin
}
}
Is it possible to make an array of UIButtons?
let buttonArray: [UIButton] = [UIButton(Button1)!, UIButton(Button2)!, UIButton(Button3)!]
To reference later as
buttonArray[0].setImage(UIImage, forState: UIControlState.Normal)
Or somehow set a
var button = UIButton.whoseName = "Specific String"
button.setImage(UIImage, forState: UIControlState.Normal)
VC1:
import UIKit
class VC1: UIViewController {
#IBOutlet weak var Card1: UIButton!
#IBOutlet weak var Card2: UIButton!
#IBOutlet weak var Card3: UIButton!
let Cards: [UIImage] = [UIImage(named: "Default")!, UIImage(named: "2s")!,UIImage(named: "2h")!,UIImage(named: "2c")!,UIImage(named: "2d")!,]
// var CardCaller: Array<UIButton> = [Card1, Card2, Card3]
let CardCallers: [UIButton] = [Card1, Card2, Card3] //ERROR: 'VC1.Type' does not have a member named 'Card1'
var caller = ""
var Index2 = Int()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let KVC = segue.destinationViewController as VC2
KVC.source = segue.identifier!
}
#IBAction func unwind(unwindSegue: UIStoryboardSegue){
//Card1.setImage(Cards[Index2], forState: UIControlState.Normal)
//let button = UIButton(named: "Card1")!
if caller == "Card1" {Card1.setImage(Cards[Index2], forState: UIControlState.Normal)} else if caller == "Card2" {Card2.setImage(Cards[Index2], forState: UIControlState.Normal)} else if caller == "Card3" {Card3.setImage(Cards[Index2], forState: UIControlState.Normal)}
}
#IBAction func text(sender: AnyObject) {
println(caller)
println(Index2)
}
}
The IBOutlets are wired properly to Storyboard buttons; I created them with control/drag to the view controller.
This shouldn't be a problem, but it may have something to do with when you're accessing the buttons. Try creating the array globally and adding the buttons to it once they've loaded:
class VC1: UIViewController {
#IBOutlet weak var Card1: UIButton!
#IBOutlet weak var Card2: UIButton!
#IBOutlet weak var Card3: UIButton!
var CardCallers: [UIButton] = [UIButton]() // Empty UIButton array
override func viewDidLoad() {
self.CardCallers = [self.Card1, self.Card2, self.Card3] // Buttons have now loaded in the view
}
}
You can.
Two ways to do it:
var buttonsArray: Array<UIButton> = [button1, button2]
Or
#IBOutlet var buttonsArray: Array<UIButton> = []
For the later one, it can be filled from the storyboard as an IBOutletCollection
Please note that views can be assigned to an IBOutlet and an IBOutletCollection at the same time.