I am trying to unhide n number of elements depending on the users input into a text field.
So the user enters a number between 1 - 5 in the text field then clicks submit which calls createSplit. As you can see, it unhides a view and then I want it to loop x (x being the number the user inputs) amount of times to unhide day(i)View textfield
#IBAction func createSplit(_ sender: Any)
{
noOfExerciseView.isHidden = false
let noOfDays: Int = Int(numberOfDays.text!)!
for i in 1...noOfDays
{
day\(i)View.isHidden = false
}
}
I have a working solution but it's not the most efficient so I hope someone can help doing this an efficient way.
#IBAction func createSplit(_ sender: Any)
{
noOfExerciseView.isHidden = false
let noOfDays: Int = Int(numberOfDays.text!)!
for i in 1...noOfDays
{
if (i==1)
{
day1View.isHidden = false
} else if (i==2)
{
day2View.isHidden = false
} else if (i==3)
{
day3View.isHidden = false
} else if (i==4)
{
day4View.isHidden = false
} else if (i==5)
{
day5View.isHidden = false
}
}
}
String interpolation cannot be used to set the name of a variable:
day\(i)View.isHidden // does not work
Your best bet is to use an outlet collection to define all your day views.
Instead of this:
#IBOutlet var day1View: UITextField!
#IBOutlet var day2View: UITextField!
#IBOutlet var day3View: UITextField!
//...
Do this:
#IBOutlet var dayViews: [UITextField]!
Then you can write your loop like this:
for i in 0...noOfDays-1
{
dayViews[i].isHidden = false
}
Note that to do this, you'll need to delete the existing outlets and reconnect them.
If you're using a storyboard, then when you Control-drag from your first text field to your class file, select Outlet Collection for the Connection type and name it dayViews. To add the remaining text fields to the collection, just Control-drag from each one to the dayViews var in your class file.
Related
I have a difficulty in a simple task. I googled this topic, but other examples are complicated by additional syntax that I don't understand yet. Can you help me to solve it or give link if there is already was similar topic.
I need to move the function responsible for selecting the button to a separate file, because if the number of buttons increases, it will turn into a large sheet. So made a function in separate swiftfile, but naturally the new file does not know about any buttons in viewController and can't find it in scope. Also If i’m not mistaken i need give Bool and return String.
How can I transfer a function with button sender to a separate file so that it returns non-optional text value back in the ViewController?
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var Label1: UILabel!
#IBOutlet weak var BTC: UIButton!
#IBOutlet weak var ETC: UIButton!
#IBOutlet weak var LTC: UIButton!
var choice = "Choose coin"
var coinType = getCoinType()
#IBAction func optionSelected(_ sender: UIButton) {
BTC.isSelected = false
ETC.isSelected = false
LTC.isSelected = false
sender.isSelected = true
if BTC.isSelected == true{
ETC.isSelected = false
LTC.isSelected = false
choice = "BTC"
Label1.text = choice
}else if ETC.isSelected == true{
BTC.isSelected = false
LTC.isSelected = false
choice = "ETC"
Label1.text = choice
}else if LTC.isSelected == true{
ETC.isSelected = false
LTC.isSelected = false
choice = "LTC"
Label1.text = choice
}
}
}
new file, i can't understand how to get sender from buttons here
import Foundation
func getCoinType() -> String{
var choice: String
// my if else function
return choice
}
P.S. In general, is it possible to make it easier, without using UIPickerView?
On how to add functions in different swift file you have a few options. This a simple one: Create a new swift file and name it ViewController+Extenstions.swift (you can use any name though). Then add an extension to your ViewController class and add your function like this:
extension ViewController {
func getCoinType() -> String {
var choice: String
// my if else function
return choice
}
}
You can add as many functions as you need and in different files (all extensions to ViewController but of course with different file names).
PS, in your optionSelected function, you are setting:
BTC.isSelected = false
ETC.isSelected = false
LTC.isSelected = false
I don't know what you're trying to achieve, but by doing so, those if-else will never be executed since your are setting the three buttons as not-selected!
UPDATE:
For your button selection problem, you can do this:
1- Add tags to your buttons
You can do it inside viewDidLoad method. This way you can differentiate between different buttons.
override func viewDidLoad() {
super.viewDidLoad()
BTC.tag = 0
ETC.tag = 1
LTC.tag = 2
}
2- Connect the action of buttons
Although your three buttons can have three different handler functions, it's easier to connect all of them to a single handler. However, we can know which button is tapped based on the value of the tag we assign in the previous step. So, connect all buttons to optionSelected(_ sender: UIButton) through Storyboard (because you have used Storyboard.
3- Rewrite getCoinType function
func getCoinType(tag: Int) -> String? {
var choice: String?
switch tag {
case 0:
choice = "BTC"
case 1:
choice = "ETC"
case 2:
choice = "LTC"
default:
choice = nil
}
return choice
}
Buttons' handler
Now when a button is tapped we call getCoinType function with that button's tag as input argument. It will return the string and we assign it to the Label1:
#IBAction func optionSelected(_ sender: UIButton) {
let choice = getCoinType(tag: sender.tag)
Label1.text = choice
}
And you're done!
I am trying to implement one button- one click to display the first message, the second click would change to second message, the third click would change to the third message.
I looked up to one possible solution is to use UITapGestureRecognizer - single tap and double tap, which means I can trigger the button (single tap to display the first message and double tap to display the second message).
However, if I have more than two lines and I just want to display them by clicking each one (like animation). Would that be possible to just deal with that inside one UIView and UIbutton?
I currently have 3 simple messages:
#IBOutlet weak var Textfield: UITextView!
#IBOutlet weak var Changingbutton: UIButton!
#IBAction func ChangingTapped(_ btn: UIButton) {
Textfield.text = "Changing to driving"
Textfield.text = "Changing to walking"
Textfield.text = "Changing to cycling"
}
The problem now is when I click the button it would just go the last message. That might not be a clever way to do so.
Thanks so much for the inputs and I am sorry if that is a rather simple question.
You can implement a custom CaseIterable enumeration to perform a loop so that you can get the next element every time you press a button:
extension CaseIterable where Self: Equatable {
var allCases: AllCases { Self.allCases }
var nextCase: Self {
let index = allCases.index(after: allCases.firstIndex(of: self)!)
guard index != allCases.endIndex else { return allCases.first! }
return allCases[index]
}
#discardableResult
mutating func next() -> Self {
self = nextCase
return self
}
}
Create a enumeration with your transportation modes:
enum Mode: String, CaseIterable {
case cycling, driving, walking
}
add a mode property to your view controller and set the initial value
var mode: Mode = .cycling
Now you can simply call the next mode method every time you press the button:
func ChangingTapped(_ btn: UIButton) {
Textfield.text = "Changing to " + mode.next().rawValue
}
Note: It is Swift naming convention to name your methods and properties starting with a lowercase letter.
Why not just set a counter and increment it every time your IBAction is activated?
var x = 0
#IBAction func ChangingTapped(_ btn: UIButton) {
if(x==0){
Textfield.text = "Changing to driving"
}
else if(x==1){
Textfield.text = "Changing to walking"
}
else{
Textfield.text = "Changing to cycling"
}
x +=1
//if x needs to be reset
/*
if(x > 2) x = 0
*/
}
I have a list of buttons inside an array. I want to replace the buttons position order using that array. I can do this in java, but cant do the same in swift. Here is my code:
#IBOutlet weak var menuView: UIView!
struct ButtonsIndex {
var button: UIButton
var index: Int
}
var footer: [ButtonsIndex] = []
//Set Buttons order etc
...
func setFooter(){
let count = 0
for buttons in menuView.subviews {
if var button = buttons as? UIButton {
button = footer[count].button
count += 1
}
}
}
Is it impossible to change the buttons position without connecting the outlets to my code? Thanks in advance.
I want to add a random number in front of my UI label this is my code which is not working.
#IBOutlet var Label2: UILabel!
#IBOutlet var Label1: UILabel!
Label1.text! = "1"
Label2.text! = "2"
var random = arc4random_uniform(2) + 1
if Label(random).text! == "1" {
print("This is Label 1")
} else {
print ("This is Label 2")
}
If there is any other way to add a random number in front of UI Label i'll welcome the answer.
Use IBOutletCollection
#IBOutlet var label: [UILabel]!
label[0].text! = "1"
label[1].text! = "2"
var random:Int = Int(arc4random_uniform(2))
if label[random].text! == "1" {
print("This is Label 1")
} else {
print ("This is Label 2")
}
UPDATE:
make sure all the labels you want in the array is highlighted
right click and drag to your collection view
set connection to Outlet Collection
You can put your labels into an array and then pick a random one:
#IBOutlet var label1: UILabel!
#IBOutlet var label2: UILabel!
var labels = [UILabel]()
override func viewDidLoad() {
super.viewDidLoad()
labels.append(label1)
labels.append(label2)
var random = Int(arc4random_uniform(2))
if labels[random].text! == "1" {
print("This is Label 1")
} else {
print ("This is Label 2")
}
}
It seems that what you're trying to achieve with Label(random) is to dynamically change the Label variable name. As pointed in other question, this is probably a bad practice. So, I would recommend you read Create a variable in swift with dynamic name, first.
[edit:]
Just to give an example, you can do that using an Array, such as:
// Creating two UILabels:
var label1 = UILabel()
var label2 = UILabel()
label1.text = "0"
label2.text = "1"
// An array of Labels, which starts from 0:
let labels: [UILabel] = [label1, label2]
// Another random function which goes to the size of the array:
var i = random() % labels.count
// Just to check the random number:
print("Your random number: \(i)")
// And then, the test:
if labels[i].text == "0" {
print("This is Label 0: \(labels[i].text)")
} else {
print ("This is Label 1: \(labels[i].text)")
}
Just apply these ideas to your IBOutlet variables.
Hope it helps :D
I'm trying to have an if statement that will make a button hidden when a label displays a certain status, and appears when the label says something else. The name of the label is Status, and when it shows "Closed", I want it hidden, and when it shows "Open", it will appear.
var query3 = PFQuery(className:"Status_of_game")
query3.findObjectsInBackgroundWithBlock{
(namelist3: [AnyObject]!, error : NSError!) -> Void in
for list3 in namelist3 {
var output = list3["StatusType"] as String
self.Status.text = output
println(output)
if self.Status.text == "Closed"
{
Purchase().enable = false
}
}
}
As #LAmasse says, you want to use button.hidden = true. button.hidden was renamed to button.isHidden in Swift 3
The code you posted doesn't make sense.
if self.Status.text == "Closed"
{
Purchase().enable = false
}
What is Purchase? From the capitalized name, it seems to be a class. If so, the expression Purchase() is likely creating a new instance of the Purchase class, which makes no sense. Why are you making a function call? If that is creating a new Purchase object then that code is pointless. (You would create a new object inside the if statement that would be discarded on the very next line since you don't keep a strong reference to it.)
You want to set up an IBOutlet for your button and connect it in Interface Builder.
The declaration might look like this:
Class MyViewController: UIViewController
{
#IBOutlet weak var theButton: UIButton!
//The rest of your view controller's code goes here
}
If the outlet is connected to your button, there should be a filled-in circle to the left of the line of code. It looks like this:
And then your code to show/hide the button might look like this:
func showQueryResults
{
var query3 = PFQuery(className:"Status_of_game")
query3.findObjectsInBackgroundWithBlock()
{
(namelist3: [AnyObject]!, error : NSError!) -> Void in
for list3 in namelist3
{
var output = list3["StatusType"] as String
self.Status.text = output
println(output)
if output == "Closed"
{
theButton.isHidden = false //changed to isHidden for Swift 3
}
}
}
}
It isn't clear to me why you'd loop though all of the results from your query and and show the button if the "StatusType" of any of the results is == "Closed".
Finally, I'm not very familiar with parse. If the completion block for the findObjectsInBackgroundWithBlock method doesn't get called on the main thread you will have to change that code to make the UI updates on the main thread.
EDIT:
I've since learned that Parse executes its completion handlers on the main thread, so you don't need to worry about UI calls from Parse completion handlers.
SWIFT 3
I created an
IBOutlet: loadingBDLogo
To Show:
loadingBDLogo.isHidden = false
To Hide:
self.loadingBDLogo.isHidden = true
The sample code for hiding a button in Swift:
import UIKit
class ViewController: UIViewController {
// Create outlet for both the button
#IBOutlet weak var button1: UIButton!
#IBOutlet weak var button2: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
//Set button2 hidden at start
button2.isHidden = true
}
//Here is the action when you press button1 which is visible
#IBAction func button1(sender: AnyObject) {
//Make button2 Visible
button2.isHidden = false
}
}
And
You have to make the UIButton a property of the class if you want to keep a reference to it. Then you can access it using self.takePhotoButton.
To hide a button, use button.hidden = true
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html#//apple_ref/occ/cl/UIView