Swift: Programmatically changing my UISegmentedControl's Items - ios

I want to change the items in my UISegmentedControl based off of another selection. I do not want to change the number of items, but simply the item labels, as well as the 'hidden' variable of the UISegmentedControl.
Here is my code to get the UISegmentedControl:
#IBOutlet weak var viewPicker: UISegmentedControl!
and here is the code to change it:
viewPicker = UISegmentedControl(items: ["Description", "Location"])
However, this doesn't work and sometimes sets viewPicker to nil, giving an error. What is the best way to do this?

Since you are declaring your variable as "weak", it will get deallocated as soon as you assign it. But you should not do it anyway, because it is #IBOutlet -> you should connect it through interface builder.
As for changing the title, instead of just creating new SC, use
self.viewPicker.setTitle("", forSegmentAtIndex: index)
And to hide / show segmented control,
self.viewPicker.hidden = true / false
Hope it helps!

The UISegmentControl has a method that lets you change the labels individually called:
setTitle(_:forSegmentAtIndex:). So you just use it on your segmented control like so:
self.viewPicker.setTitle("Description", forSegmentAtIndex:0)
self.viewPicker.setTitle("Location", forSegmentAtIndex:1)

For Swift 3.0 use:
self.viewPicker.setTitle("Description", forSegmentAt: 0)
self.viewPicker.setTitle("Location", forSegmentAt: 1)

Related

Show or hide items by clicking button

I have four imageview contents in an XIB and a button that covers all my XIB. I want to make when the user tap the button, the first imageview is shown, the next tap is hidden and the second imageview is displayed and so on until all my imageview is shown / hidden. What would be the most efficient way to do it?
Save all your UIImageViews to an array, and current showing imageView to a variable, it may look like this:
var imageViews: [UIImageView] = []
var currentImageViewIndex = 0 {
didSet {
if currentImageViewIndex >= imageViews.count { currentImageViewIndex = 0 }
imageViews[oldValue].isHidden = true
imageViews[currentImageViewIndex].isHidden = false
}
}
func handleTap() {
currentImageViewIndex += 1
}
I suggest you use a state variable that contains an enum listing the various states (firstImageVisible, secondImage.... ) then you can have a function inside the enum that switches to the nextState (being the target of your button action) you can also easily iterate through states of an enum, check the documentation for the CaseIterable protocol. Often having a property observer (didSet) on the state is a handy place to update other parts of the UI which need to change every time the state changes.

Setting a button image depending on another variable? Swift

so I'm very new to swift. I currently have 16 buttons all set to individual outlets box1,box2,box3 etc.
Each box I have set a tag and what I am trying to do is set the image of a particular box based off another integer variable to determine which box I'm changing.
So say I do a calculation and index = 4.
Is there a way I can then set box(index).setImage?
I understand this probably isn't the best way to do it or even possible, maybe I can set each button to an array of objects instead? Any tips would be great.
If you want to set the image of button through some tag then you don't need any outlets for the buttons.
You can change your button image by finding the button through viewWithTag() property.
Here is the code
var button = self.view.viewWithTag(Your_Calculated_Index) as! UIButton
button.setImage(Your_Image, for: .normal)
You can try this. You need to create an array for the button.
#IBOutlet var allbtns: [UIButton]!
for buttons in allbtns{
if buttons.tag == 4{
print("Button 4 ");
buttons.setImage(UIImage(named: "imagname"), for: UIControlState.normal)
}else{
print("Other buttons except 4 ");
}
}

Dynamic Label Titles

I have an app I am working on where it shows a balance for users that changes. I would like to display these values as they change and the only way I know how to do that would be with a button. But the values often change on a different view controller so I was wondering if I can set labels equal to a variable that update along with those variables.
Since the values change outside of the view controllers with the labels, the normal way I change labels, using a button, does not apply.
Thanks in advance!
As a general solution, you could achieve this by declaring a property observer in your view controller, example:
class ViewController: UIViewController {
var updatedData = "" {
didSet {
lblData.text = "Data: \(updatedData)"
}
}
#IBOutlet weak var lblData: UILabel!
}
At this point, each time updatedData value is edited, the lblData label text will be updated.
Note that there is also willSet option which is called just before the value is stored, for more information, you could check Swift Properties Documentation - Property Observers.

Changing text of Swift UILabel

I am attempting to learn Apple's Swift. I was recently trying to build a GUI app, but I have a question:
How do I interact with GUI elements of my app? For instance, I used interface builder to make a UILabel, and I connected it to my viewcontroller by control-clicking, so that I get the #IBOUTLET thing. Now, how do I, while in my view controller, edit the text of this UILabel? To state it another way, what code can I use to programatically control the text of something on my storyboard? All methods I have found online only appear to work with a button generated in code, not a button generated on a storyboard.
I've seen code like
self.simpleLabel.text = "message"
If this is right, how do I link it with the label in question? In other words, how do I adapt this code to be connected with the IBOutlet (If that's what I do)
If you've successfully linked the control with an IBOutlet on your UIViewController class, then the property is added to it and you would simply replace simpleLabel with whatever you named your IBOutlet connection to be like so:
class MyViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
func someFunction() {
self.myLabel.text = "text"
}
}
The outlet you created must've been named by you. The outlet belongs to your view controller. self.simpleLabel means 'fetch the value of my property named 'simpleLabel'.
Since different outlets have different names, using self.simpleLabel here won't work until your outlet is named 'simpleLabel'. Try replacing 'simpleLabel' with the name you gave to the outlet when you created it.
The correct way now would be:
self.yourLabelName.text = "message"
If you have something like this for an IBOutlet:
#IBOutlet var someLabel: UILabel!
then you could set the text property just like in your example:
someLabel.text = "Whatever text"
If you're having problems with this, perhaps you're not assigning the text property in the right place. If it's in a function that doesn't get called, that line won't execute, and the text property won't change. Try overriding the viewDidLoad function, and put the line in there, like this:
override func viewDidLoad() {
super.viewDidLoad()
someLabel.text = "Whatever text"
}
Then, as soon as the view loads, you'll set the text property. If you're not sure if a line of code is executing or not, you can always put a breakpoint there, or add some output. Something like
println("Checkpoint")
inside a block of code you're unsure about could really help you see when and if it runs.
Hope this helps.
You may trying to change a UI component not in the main thread, in that case, do this:
DispatchQueue.main.async {
someLabel.text = "Whatever text"
}

Swift put multiple IBOutlets in an Array

I made these (marked with red border) IBOutlets using ctrl + drag
But i don't like to have the exact same line 9 times (DRY)
How do i put these IBOutlets in an Array?
you can define a generic outlet collection in Swift like this:
#IBOutlet var collectionOfViews: Array<UIView>? // = [UIView]?
or for e.g. UIButton objects:
#IBOutlet var collectionOfButtons: Array<UIButton>? // = [UIButton]?
you can find your collections under the Outlet Collections group as usually are in the File's Owner:
it would look on my console after connecting 5 random buttons:
Follow these steps to create an array of outlets an connect it with IB Elements:
Create an array of IBOutlets
Add multiple UIElements (Views) in your Storyboard ViewController interface
Select ViewController (In storyboard) and open connection inspector
There is option 'Outlet Collections' in connection inspector (You will see an array of outlets there)
Connect if with your interface elements
-
class ViewController2: UIViewController {
#IBOutlet var collection:[UIView]!
override func viewDidLoad() {
super.viewDidLoad()
}
}
Solution here Swift - IBOutletCollection equivalent
#IBOutlet var objectCollection: [Object]
This is for macOS (should be similar for iOS) and I do not find an "Outlet Collections" in my storyboard (looks like they took that option out). So I put all my buttons in an NSStackView and linked the stack from storyboard
#IBOutlet weak var buttons: NSStackView!
and then I looped over them to make changes accordingly
for case let (index, button as NSButton) in buttons.arrangedSubviews.enumerated() {
if(index + 1 != someButtonIndex) {button.state = .off}
else {button.state = .on}
}
you can also use tag instead of index
Start with the two view pane where you see both your code and the storyboard. When you make your first IBOutlet connection from the UI to your code, just look carefully at the Connection drop down field and select the option called "Outlet Collection". This will automatically create an array of IBOutlets. Next just look for the little black circle within a circle that is placed in your code where the array is created. Just drag from this circle to all the other UI objects you want to connect to that same collection (not sure if you can mix types). Similarly you can connect all the objects to one Action by dragging from the first black dot created to all the other objects you want to wire up to that action. Also consider EnumerateSequence() to help in working with this Collection. Sweet right?

Resources