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).
Related
I am building Application in iOS swift 3.0. I am creating dynamic UIViews. I need to remove custom view randomly, But currently I am unable to relocate the positions as I get the gaps between the two views and I want remove them, as shows in the picture with code below, Kindly help me with this.
class ViewController: UIViewController {
var myView: subView!
var y : CGFloat!
var tag : Int = 0
#IBOutlet weak var addButton: UIButton!
override func viewDidLoad() {
y = 1
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func cancelbutton(_ sender: UIButton)
{
let selectViewTagValue : Int = sender.tag /// save the selected view tag value
for object in self.view.subviews {
if ((object is subView) && object.tag == selectViewTagValue)
{
object.removeFromSuperview()
}
}
}
#IBAction func buttonAction(_ sender: Any) {
y = y + 110
myView = subView(frame: CGRect(x: 80, y: y, width: 300, height: 100))
myView.tag = tag
myView.actionButton.tag = tag
tag = tag + 1
myView.backgroundColor = UIColor.green
myView.actionButton.addTarget(self, action: (#selector(cancelbutton(_:))), for: UIControlEvents.touchUpInside)
self.view.addSubview(myView)
}
Please Help me this issue... "Thanks in advance"
When you have multiple similar views to be displayed and re-arranged dynamically, UITableView is a smart choice. Re-arranging frames would be tedious to maintain and requires lot of code to implement. Why not use tools provided by UITableView? Just use deleteRowsAtIndexPaths to delete your view and the rest will be taken care for you.
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
}
I am relatively new to swift and have been used to a JavaScript environment so correct me if it is not possible, but is there a way to dynamically add rows of text inputs and thus data in the form of a nested dictionary, from the view via a button?
I am looking to create an object with no set constraints on the limitations of data.
Essentially the object would be structured as:
"Object1": ["row1":[desc: "desc1", option: "option1"]]
and when a user adds a row through a UIButton:
"Object1": ["row1":[desc: "desc1", option: "option1"], "row2": [desc: "desc2", option: "option2"]]
and so on....
Image example of what I am looking to achieve
Thank you for any input provided.
With the feedback of Will M I did overthink this again and came up with another solution:
class ViewController: UIViewController {
let xPos : CGFloat = 0
var yPos : CGFloat = 0
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 press(sender: AnyObject) {
yPos += 22
let tf = UITextField()
tf.frame = CGRectMake(xPos, yPos, 100, 20)
tf.backgroundColor = UIColor.blackColor()
self.view.addSubview(tf)
}
}
Here is a screenshot of what the result looks like I hope this helps you!
http://imgur.com/m59xDfN
The black things are textfields
I'm making app and I'm trying to make a View which contains a Label with a question. I want this view in my app and because I will use it repeatedly, I made a class (If I want to make some change, I can do It from one place). The UIView is called questionView (var questionView = UIView()). Problem is when I want to make questionView a subview of view. The error says that I don't have have "view" which I understand. I don't have view but how can I get it? Thank you
This is what is inside my Question class:
import Foundation
import UIKit
class Question {
// PROPERTIES:
var questionLabel = UILabel()
var questionView = UIView()
// METHODS:
func createQuestion (input:String) {
// some code .... not important
// THIS:
self.view.addSubview(questionView)
}
// ... next code, also not important
}
UPDATE:
There is my solution. It works BUT I think that it's not correct from a programming standpoint. Can anybody tell me anything about it? Thank you
My class in separate swift file:
My class in separate swift file:
class LabelClass {
var view = UIView()
init (view: UIView) {
self.view = view
}
var lbl = UILabel()
var lblView = UIView()
func makeLabel () {
self.lbl.frame = CGRectMake(0, 0, 150, 50)
self.lbl.text = "Text text text"
self.lbl.numberOfLines = 0
self.lblView.frame = CGRectMake(20, 20, 150, 50)
self.lblView.addSubview(self.lbl)
self.view.addSubview(lblView)
}
}
Piece of code my ViewController.swift:
override func viewDidLoad() {
super.viewDidLoad()
// Added code:
var object = LabelClass(view: self.view)
object.makeLabel()
}
I don't know Swift, but as far as I know, only instances of UIViewController have a view property, the class Question does not, so you cannot add subviews to it.
What you probably want is making a subclass of UIView which contains a question label, or to add the questionLabel as a subview of questionView.
It is because you are trying to add your view to a normal Swift class which doesn't have a self.view instance. Your Question class must be a subclass of UIViewController cocoa class that it has a self.view instance and override methods.
class Question:UIViewController {
// PROPHERITIES:
var questionLabel = UILabel()
var questionView = UIView()
// METHODS:
override func viewDidLoad() {
createQuestion("foo")
}
func createQuestion (input:String) {
// some code .... not important
// THIS:
self.view.addSubview(questionView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// ... next code, also not important
}
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 = []