How to create an array of UITextField objects in Swift? - ios

I am working on an application in Swift. At the beginning I provide number of inputs that I would like to add. In next view I create as many UITextFields as I defined in first view.I have a problem with storing of all this values from TextFields after pressing the button. It seems to me that the most effective solution is to create an array of UITextFields and add every value of TextField into array and then in action for button adding values which are in all TextFields into array. Unfortunately, it doesn't work. Any suggestions? Thanks in advance.
override func viewDidLoad() {
super.viewDidLoad()
var counter = 0
for i in 1...mainInstance.numberOfInputs
{
super.viewDidLoad()
array.insert(UITextField(frame: CGRect(x: 0, y: 50, width: 60, height: 20)), at: i)
array[i].center = CGPoint(x: 200,y: 50 + counter)
array[i].textAlignment = NSTextAlignment.center
array[i].layer.borderWidth = 1
array[i].layer.borderColor = UIColor.black.cgColor
self.outletScrollView.addSubview(array[i])
counter += 50
}
super.viewDidLoad()
let button = UIButton(type: .system) // let preferred over var here
button.frame = CGRect(x: 200, y: 50 + counter, width: 100, height: 20)
button.setTitle("Recalculate", for: UIControlState.normal)
button.addTarget(self, action: "actionRecalculate:", for: UIControlEvents.touchUpInside)
self.outletScrollView.addSubview(button)
outletScrollView.contentInset = UIEdgeInsetsMake(0, 0, CGFloat(counter+100), 0)
}

You could create easily with:
let textFields = [UITextField]()
You should consider using an UIScrollView, (like in your example) or (better idea in my opinon) a UITableView to add your UITextfields. So you have multiple Rows, and every row has one UITextField. The number of rows / Textfield can u easily customize (and get it from your FirstViewController for example).
Just create a custom UITableViewCell - add an UITextField and connect the IBOutlet. To get the values from every UITextField you could iterate through all cells, and read out the values. Just ask, if you need more help about doing that.

Creating array of UITextfield could be done this way
// Create an empty array of type UITextField
var listOfTextFields : [UITextField] = []
// In viewDidLoad, create a textfield and add it to the array
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...mainInstance.numberOfInputs-1 {
let textField = UITextField((frame: CGRect(x: X, y: Y*i, width: yourWidth, height: yourHeight)))
textField.delegate = self
listOfTextFields.append(textField)
}
}
In this UITextField setup, I didn't account for any formatting to shorten the answer.

Though this might not be for the exact use case, it could help others with similar use cases (particularly programmatically created textfields or custom uicell).
txtfield.tag = indexPath.row // or other int
Then you implement textfield didEndEditing after array has been initialized and delegating
#IBAction func endedEditing(_ sender: UITextField) {
arr[sender.tag] = sender.text
}

Related

custom UITableViewCell button isn't executing its function

I have a tableview in my view controller with a custom cell. in the cell I have a function that is suppose to do something. I have a print statement that is getting executed.
#objc func cellButtonTapped() {
cellText.backgroundColor = .red
print("cell button tapped")
}
when I tap the button I do see in my console the print statement, but its not changing the cell background color like I want it to.
this is the cellText in the tableViewCell
let cellText : UITextField = {
let cellText = UITextField()
cellText.isUserInteractionEnabled = false
return cellText
}()
this is how its layout is in the cell. I don't think its layout is important
override func layoutSubviews() {
super.layoutSubviews()
contentView.addSubview(cellText)
contentView.addSubview(cellButton)
cellText.frame = CGRect(x: 0,
y: 0,
width: contentView.width - 30,
height: contentView.height)
cellButton.frame = CGRect(x: cellText.right, y: 0, width: 30, height: contentView.height)
}
what I had to do is create a variable in the viewController with the value that the cell needs. in my case I wanted a bool value to be carried over.
var isBool : Bool = false
then I let the function for the button to change the variable value:
#objc func sendButtonTapped() {
isBool = !isBool
tableView.reloadData()
print("send button tapped")
}
the function here changes the value of my bool every time I click the button.
I transferred the value to the cell with the cellForRowAt in the tableview.

changing a programmatically made UIButton to UILabel within certain textFields or stackViews?

Beginner Swift programmer here and new to stack overflow.
I am trying to make a simple task list/toDoPlanner, kinda similar to Apple's reminders app on the iPhone.
My goal is for this specific problem is that when a user clicks on the UIButton within a certain textField (which is within a stackView), that UIButton should change to a UILabel.
Here is how I make a button appear after a user finishes typing a task. This works fine:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
if(textField == textField1) // if the first text field is pressed
{
let image = UIImage(named: "To Be Completed Circle.png")
button = UIButton(frame: CGRect(x: 340, y: 56, width: 30, height: 30));
button.setBackgroundImage(image, for: UIControlState.normal)
self.view.addSubview(button)
button.addTarget(self, action:#selector(self.pressed), for: .touchUpInside)
}
...
And then here is how I am trying to change the UIButton when the user clicks it to change that button into a UILabel:
func pressed(textField: UITextField!) {
let image = UIImage(named: "Checkmark.png")
if(textField == textField1)
{
button.removeFromSuperview()
let label = UILabel(frame: CGRect(x : 340, y :56, width: 30, height: 30))
label.backgroundColor = UIColor(patternImage: image!)
self.view.addSubview(label)
}
The whole if block isn't being read, and I am not too sure why. I am assuming it has to do with separate properties of the UIButton and the UITextField.
Any help is appreciated and any other tips for programming in iOS is helpful!
Let me know if you need more details.
Your textField is not associated with the button, even though you are creating it with the textFieldShouldReturn function. So your target (self.pressed) does not receive any textField parameter, and will be nil. Thus, your textField == textField1 will never be true.
If you're implementing a task list, an easier way would be to add each new task to a tableView. Then you would be able to associate a button and label (For the task name) with a section & row.
It would also be much easier to change the image of the button instead of removing it and creating a UILabel in it's place.

How to remove multiple buttons that I created with a loop?

EXPLANATION:
1) I initiate the button above the class :
var myButton = UIButton()
2) I then create x amount of buttons depending on how many items are in an array
for letter in arrayOfLetters {
myButton = UIButton(frame: CGRect(x: buttonX, y: 500, width: someFloat, height: someFloat))
buttonX = buttonX + thirdFloat //spacing
myButton.layer.cornerRadius = 5
myButton.backgroundColor = UIColor.darkGrayColor()
myButton.setTitle("\(letter)", forState: UIControlState.Normal)
myButton.titleLabel?.text = "\(letter)"
myButton.addTarget(self, action: "myButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(myButton)
}
3) Later on once the user has pressed the correct buttons, I call a function to refresh and I want to remove all buttons. This is so I can generate new buttons based on new array
myButton.removeFromSuperview()
ISSUE:
However this does nothing, I tried giving the buttons a tag and deleting buttons by tag == tagId but nothing happened.
I can delete all views but it deletes everything else,
I tried this but again nothing happends
var buttons = [myButton]
for button in buttons as! [UIButton] {
button.removeFromSuperview()
}
I want to delete all buttons I added and i'm either not deleting them or deleting everything in the view
EASY FIX:
1) Inside Class, out of any func:
var buttonsArray = [UIButton]()
2) Declare myButton here and add the append line:
for letter in arrayOfLetters {
var myButton = UIButton(frame: CGRect(x: buttonX, y: 500, width: someFloat, height: someFloat))
...
self.buttonsArray.append(myButton)
}
3) To remove buttons:
for btn in buttonsArray {
btn.removeFromSuperview()
}
EXPLANATION:
Always store in an array the elements you create with a loop if you want to easily remove all of them at once.
i hope it will help for you give tag for your button while you are adding delete that button
for button in self.view.subviews {
if button.tag == 100 {
button.removeFromSuperview()
}
}
you are re-assigning the myButton variable as you loop.
Remove this line:
var myButton = UIButton()
add a property at the top to hold the buttons:
var buttons:[UIButton]()
then later in your code:
for letter in arrayOfLetters {
var myButton = UIButton(frame: CGRect(x: buttonX, y: 500, width: someFloat, height: someFloat))
buttonX = buttonX + thirdFloat //spacing
myButton.layer.cornerRadius = 5
myButton.backgroundColor = UIColor.darkGrayColor()
myButton.setTitle("\(letter)", forState: UIControlState.Normal)
myButton.titleLabel?.text = "\(letter)"
myButton.addTarget(self, action: "myButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(myButton)
self.buttons.append(myButton)
}
Then you should be able to remove like so:
for button in self.buttons {
button.removeFromSuperview()
}
This should resolve your issue, But it's important to understand what the problem was, so you define a new button as a property with this line: var myButton = UIButton(). This holds ONE button. as you are looping through creating buttons you are overriding the button with the next one.
So if anything, Calling myButton.removeFromSuperView() will remove the last one you created. Doing it the way I suggested means you create a button and add it to an array of buttons, so later you can iterate over the array referencing each button in turn and remove it.

Swift iOS : Delete UITextField with button

I'm creating a textfields in viewDidLoad and i have a add new textfield button. I'm adding new textfields, but not deleting. I just don't do it because i am new. Here is my addNewTextField button func :
#IBAction func addNewTextField(sender: AnyObject) {
var myTextField: UITextField = UITextField(frame: CGRect(x: 0, y:0, width: 200.00,height: 240.00));
myTextField.placeholder = "write something"
myTextField.center = CGPointMake(160, CGFloat(height2))
height2 = height2 + 50;
self.arrayOfTextFields.append(myTextField)
self.view.addSubview(myTextField)
}
How can i delete this textfields and arrays with another button ?
You can create a new func or IBAction and create a loop to go through all of the elements in self.arrayOfTextfields. You can then grab each textfield from the array and remove it from the superview. When the loop is finished, you can clear the array.
Something like this:
for textField in arrayOfTextFields {
textField.removeFromSuperview()
}
arrayOfTextFields = []

Can't interact with UIStepper

I'm adding a few UISteppers and UITextFields programmatically, based on user's preferences. However, I can't seem to get the UIStepper touch to click - it looks like it's not registering the touch on the -/+ buttons. I tried setting User Interaction of the userTriggers UIView to disabled, but that didn't work.
1) What else can I try?
2) I also need to be able to increment the corresponding UITextField, and then write that into my UserData.plist file, and I'm not sure how to access each field. Should I add them to an array of some sort?
import UIKit
class TriggersViewController: UIViewController{
#IBOutlet var userTriggers:UIView!
#IBOutlet var saveButton:UIButton!
var triggersList:Array<String>!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadTriggers()
var prevInput = 250;
for index in 0..<triggersList.count{
//label for trigger
var label = UILabel(frame: CGRectMake(0, 0, 200, 21))
label.center = CGPointMake(120, CGFloat(prevInput))
label.textAlignment = NSTextAlignment.Left
label.text = triggersList[index]
userTriggers.addSubview(label)
//input box for trigger
var input = UITextField(frame: CGRectMake(0, 0, 50, 21))
input.center = CGPointMake(250, CGFloat(prevInput))
input.text = "0";
//add input to triggersView
userTriggers.addSubview(input);
//UIStepper
var stepper = UIStepper(frame: CGRectMake(0, 0, 50, 21))
stepper.center = CGPointMake(300, CGFloat(prevInput))
stepper.addTarget(self, action: "stepperValueChanged:", forControlEvents: .ValueChanged)
stepper.enabled = true
//add stepper to triggersView
userTriggers.addSubview(stepper);
prevInput += 50 //increment for height
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func stepperValueChanged(sender:UIStepper!){
println("It Works, Value is -->\(Int(sender.value).description)")
}
func loadTriggers(){
var myDict: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("UserConfigs", ofType: "plist") {
myDict = NSDictionary(contentsOfFile: path)
}
if let dict = myDict {
triggersList = dict["Triggers"] as Array<String>
}
}
}
You actually need to set user interaction on the superview to enabled. See here for more info: UIView -- "user interaction enabled" false on parent but true on child?
Also, re: second question an easy (but not so ideal) way to access each field is using tags. Clean-ish way to do that is define tags using an enum. Then access the fields using viewWithTag.
However, there are better ways than tags (e.g. they're not very error-proof because any view can be given any tag). If it's only a few text fields / steppers though you could just as easily add properties to your view controller for each one. The best solution would be to group the steppers and fields together in a UIView subclass (assuming they're next to each other) and store references to those groupings in your view controller (possibly in an array).

Resources