Make App Pie

Training for Developers and Artists

How to Make Dynamic UIButtons in Swift

Story boards are great — most of the time.  Where they fail miserably is in dynamic placement of controls such as buttons.  Some applications will change the number or position of buttons due to user input. In those cases, you need to use a programmatic button instead of a storyboard. In this lesson we’ll introduce using UIButton and a few other controls programmatically, and how to do some simple dynamic layout with controls.

Setting Up the Storyboard

We can get very complicated very quickly with the layout of buttons. Both Programmatic Auto Layout and Programmatic Stack Views work here. Until the bonus section at the end of this tutorial, I’m going to keep this simple and use a stack view from the storyboard to focus on the controls. Check out the links above to learn how to use these other methods.

Make a new single-view project in Xcode named SwiftButtonDemo, with Swift for the language and a Universal Device.  Save the project and go to the storyboard. Find the Vertical Stack View in the object library.

2016-04-14_05-28-27

Drag a Vertical Stack View on the storyboard. Click the auto layout pin button 2016-04-14_05-28-55 and pin the stack view up 20 points, down 20 points, left 0 and right 0 points. Update the frames with Items of New Constraints.

2016-04-14_05-30-37

Click the Add the 4 Constraints button. Your stack view now covers much of the storyboard

2016-04-14_05-30-09

In the attributes inspector, set the attributes  to Vertical Axis, an Alignment of Fill and a Distribution of Fill Equally.

2016-04-14_05-29-40

Open the assistant editor in automatic mode so you see ViewController.Swift in the assistant editor. Control-drag  from the stack view to the to the code, making a new outlet mainStackView.  We’re done with our story board work, making a quick stack view to use for later parts of the lesson. If you want to do this programmatically, see the lesson on Programmatic Stack Views for guidance.

Making a Basic Button Programmatically

Close the assistant editor. Go to the ViewController class.  Change the background of the view for the controller to dark gray. Change the viewDidLoad method to this:

override func viewDidLoad() {
    super.viewDidLoad()
    //background color for the view
    view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)

}

Above viewDidLoad, add the following method:

//MARK: View Making methods
func makeButtonWithText(text:String) -> UIButton {
    let myButton = UIButton(type: UIButtonType.System)
    return myButton
}

The function returns a UIButton, but one without configuration. We create a system button called my button and return it. The rest of our code configures our button. If we want to explicitly place the button somewhere on-screen, we will have to set the frame for the button. Change the code to this:

func makeButtonWithText(text:String) -> UIButton {
    let myButton = UIButton(type: UIButtonType.System)
     //Set a frame for the button. Ignored in AutoLayout/ Stack Views
     myButton.frame = CGRect(x: 30, y: 30, width: 150, height: 150)
    return myButton
}

For those not familiar with CGFrame,  a CGFrame sets an origin of the view in its superview’s coordinate system, and the size of the view using a rectangle defined by the core graphics type  CGRect. Our button will appear with its upper left corner at 30 across and 30 down from the upper left corner of the device with a width of 150 and a height of 150.
UIButtons have a transparent background by default. We can change the background color of the button to show the rectangle of the button. Change the code to this:

func makeButtonWithText(text:String) -> UIButton {
    let myButton = UIButton(type: UIButtonType.System)
     //Set a frame for the button. Ignored in AutoLayout/ Stack Views
     myButton.frame = CGRect(x: 30, y: 30, width: 150, height: 150)
     //Set background color
     myButton.backgroundColor = UIColor.blueColor()
    return myButton

We can have a visible button now. We’ve used methods for UIView so far. The code above works for any UIView. If you were to change UIButton to UILabel or UIView for example,  it would look exactly the same on screen.

However if you were to build and run now, you would still see nothing. When you use controls programmatically, you have to add the controls to the controllers view. Change the viewDidLoad method to this:

override func viewDidLoad() {
    super.viewDidLoad()
    //background color for the view
    view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
    //Iteration 1: Make a button
    view.addSubview(makeButtonWithText("Indie Button"))
}

The view.addSubview adds the new button to the view. Build and run. We get a square button.

2016-04-14_06-17-01

Adding State-Sensitive attributes

Buttons have different states. Unlike other controls like UILabel, the title of the button is dependent on the state of the button. You cannot directly set the title with a property. Buttons change their text based on their state. Two of the most important is the .Normal and .Highlighted state. The .Normal state is the everyday one. Most often it will be all you need to add. Add the highlighted lines to the makeButtonWithText method.

//MARK: View Making methods
func makeButtonWithText(text:String) -> UIButton {
    //Initalize a button
    let myButton = UIButton(type: UIButtonType.System)        
    //Set a frame for the button. Ignored in AutoLayout/ Stack Views
    myButton.frame = CGRect(x: 30, y: 30, width: 150, height: 150)
   //Set background color
   myButton.backgroundColor = UIColor.blueColor()       
   //State dependent properties title and title color
   myButton.setTitle(text, forState: .Normal)
   myButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
   return myButton
}

Both the title and the title color change depending on state using the setTitle:forState: and setTitleColor:forState: methods. There are several other attributes you can control by state, including attributed text for the title, a shadow on the title, and foreground and background images. We are set up for the .Normal state. Build and run. You now see the title.

2016-04-14_06-40-02

Hold down the button and the text disappears.

2016-04-14_06-17-01

A pressed button is in the .Highlighted state. Usually we tap quickly and the button seems to flash, so the highlighted state is often ignored. However, you can set the title in the highlighted state. Under the last two lines we added, add this:

 myButton.setTitle("Touched!!", forState: .Highlighted)
myButton.setTitleColor(UIColor.orangeColor(), forState: .Highlighted)        

Build and run. Hold down the button and we now see the highlighted state.

2016-04-14_06-59-00

We can add background images to the button’s state. Download the following image of the sliceofAppPie.com logo by right clicking on it and saving the image as sliceofapppie400x400black1.png:

sliceOfAppPie400x400Black

Go to the Assets.xcassets folder.

2016-04-14_07-06-54

From the folder you downloaded it to, Drag the image into the white space of the assets folder. An image will get added to your assets.

2016-04-14_07-12-44

Add this above the stack view outlet declaration so we only have to load the image once:

let image = UIImage(named:"sliceOfAppPie400x400Black1")

Add the highlighted line 14 to the makeButtonWithText method.

func makeButtonWithText(text:String) -> UIButton {
    //Initialize a button
    let myButton = UIButton(type: UIButtonType.System)   
    //Set a frame for the button. Ignored in AutoLayout/ Stack Views
    myButton.frame = CGRect(x: 30, y: 30, width: 150, height: 150)
    //Set background and tint colors
    myButton.backgroundColor = UIColor.blueColor()
    //State dependent properties title and title color
    myButton.setTitle(text, forState: .Normal)
    myButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    myButton.setTitle("Touched!!", forState: .Highlighted)
    myButton.setTitleColor(UIColor.yellowColor(), forState: .Highlighted)
    //highlighted background image
    myButton.setBackgroundImage(image, forState: .Highlighted)
    return myButton
    }

Line 14 applies the image to the background for the .Highlighted state.
Build and run. Hold down the button and you see the image.

2016-04-14_07-24-48

The image is behind the background color and highlighting  layers. You can use the background layer to make background images have a color tone. You can also shut off background color by commenting out the background color. However, it is still behind the highlight layer, and will appear dim.

Adding Actions to the Button

In Interface Builder, we control drag to code to make actions and outlets. In code we don’t have outlets and actions. Our identifier is our outlet. Instead of actions we have selectors. Selectors are just functions in our code. We use an addAction method to add the action for a specific event. Add the following to the makeButtonWithText, just above the return myButton line:

//Assign a target (i.e. action) to the button
myButton.addTarget(self,
    action: #selector(helloButton),
    forControlEvents: .TouchUpInside
)

We assign the target to self, with an action of #selector(helloButton). The #selector() tells us this is a selector, and we’ll run the function helloButton when we have an event of .TouchUpInside, when the user’s finger has left the button.

We’ll have to define our selector. Add the following function to the ViewController Class:

//MARK: - Actions and Selectors
@IBAction func helloButton(sender:UIButton){
    if myLabel.text !=  sender.titleLabel?.text {
        myLabel.text = sender.titleLabel?.text
    } else {
        myLabel.text = "Hello Pizza"
    }
}

I added the @IBAction in front of the function. You can do this if you want for documentation purposes, but it is completely meaningless in the context of a selector. AS I’ll do int the rest of this lesson, you can leave it off. For good organization and documentation, I do group actions and selectors together with a //MARK: comment.

The helloButton function will set the text of a label to either the title of the label, or the string Hello Pizza It uses a label, and we need to define one.

The Outlet Equivalent in Programmatic Code

I mentioned earlier that outlets don’t exist in programmatic controls, just identifiers. That is not completely accurate. For something that doesn’t need a true outlet, like myButton, any identifier will do anywhere in your code. However, scope rules make myButton inaccessible if I wanted to change the title somewhere outside the makeButtonWithText function. The label myLabel needs to be accessible anywhere in the class. We therefore make it a property of the class. Just under the stack view’s outlet, add the highlighted line:

//MARK: - Constants, Outlets and Properties
    let image = UIImage(named:"sliceOfAppPie400x400Black1")
    @IBOutlet weak var mainStackView: UIStackView!
    let myLabel = UILabel()
 

You don’t need to get fancy with this property. If necessary for your application, you could make it an optional value, but that is about it. Now you can define your label. Add this function:

func configureLabelWithText(text:String){
   //Set the attributes of the label
   myLabel.frame = CGRect(x: 30, y: 200, width: 150, height: 36)
   myLabel.textColor = UIColor.grayColor()
   myLabel.font = UIFont(name: "Chalkduster", size: 18)
   myLabel.text = text
   myLabel.textAlignment = .Right
}

This function sets the attributes for our label, using right-justified 18 point gray Chalkduster and the text we specified in the parameter. We’ll place it in the superview 30 points left and 200 down. We need to add it to the view. Change viewDidLoad to this:

override func viewDidLoad() {
        super.viewDidLoad()
        //background color for the view
        view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
        //Iteration 2: Make a Button and a label
        view.addSubview(makeButtonWithText("Indie Button"))
        configureLabelWithText("Hello, Label")
        view.addSubview(myLabel)
}

We’ve added our equivalent of an action and the equivalent of an outlet for the label. Build and run.

2016-04-14_08-14-17

Tap the button. The label responds by changing to the button title.

2016-04-14_08-14-35

Tap the button again. The label changes again to Hello Pizza

2016-04-14_08-14-53

Adaptive Layout and UIView Controls

There’s a problem with using frames on controls. Change the vertical position of our label from 200 to 600 points.

myLabel.frame = CGRect(x: 30, y: 600, width: 150, height: 36)

Build and run again. Press Command-Right Arrow to rotate into landscape.

2016-04-14_08-24-03

The label disappears off the bottom of the screen. Rotate back to landscape with a Command-Left arrow and it reappears.

2016-04-14_08-24-34

If you were to change to a iPhone 4s simulator, the label would disappear again. The screen is too small.

2016-04-14_08-27-53

Frames are absolute positions. They don’t move or change on different devices. On smaller devices, the label falls off the screen. You have to write code to find the device and orientation, and change all your frames to fit. This is the reason for auto layout and adaptive layout in general. It organizes your views to fit for all devices automatically.

Auto layout does take some work to understand. I’ve covered the basics elsewhere for programmatic and written a book for the storyboard. We’re not going to do that here. Instead we’ll use that stack view we made earlier to do some dynamic layout.

If you’ve set your stack view in the storyboard like we did at the start of this lesson, we can make a lot of changes with a single new method. The UIStackView instance method addArrangedSubview adds a view to the end of UIStackview‘s array of views, stored int the property arrangedSubview. We use this in place of addSubview. Once in a stack view, auto layout does the work of sizing and positioning the button. Setting the frame becomes irrelevant. Change viewDidLoad to this:

override func viewDidLoad() {
    super.viewDidLoad()
    //background color for the view
    view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
    //Iteration 3:Button and label in stack view
    mainStackView.addArrangedSubview(configureLabelWithText("Hello, Label"))
    mainStackView.addArrangedSubview(makeButtonWithText("Hello,Button"))
    mainStackView.addArrangedSubview(makeButtonWithText("Hello,Button 2"))
    mainStackView.addArrangedSubview(makeButtonWithText("Hello,Button 3"))
}

Build and run using an iPhone6s plus simulator. You get the label and three buttons. However, the buttons are squashed against each other, so they form a solid blue back ground.

2016-04-16_10-20-57

Add to viewdidload the following line

mainStackView.spacing = 5.0

Another useful property of UIStackview, spacing, puts a 5 point space between the buttons. Run again, and we can see the buttons better.

2016-04-16_10-20-59

Rotate the device and everything re-arranges.

2016-04-16_10-21-01

Everything fits even on the iPhone 4s.

2016-04-16_10-21-02

Press the Hello,Button 3 button. Since all the buttons have the same target they run the same code, and display themselves on the label.

2016-04-16_10-21-03

Dynamically Changing Attributes for Buttons

So far we’ve been adding buttons manually in viewDidLoad. The power of programmatic controls is we assign everything at run time. We can make those buttons in code with a simple loop. Add this to our ViewController class:

func rainbowButtons(count count:Int){
    for i in 1...count{
       let titleString = String(format:"Hello Button %i",i)
       let button = makeButtonWithText(titleString)
       mainStackView.addArrangedSubview(button)
    }
}

We generate a string for the title from the count of our loop, make a button and add it to the stack view. Change viewDidLoad to this:

override func viewDidLoad() {
    super.viewDidLoad()
    //background color for the view
    view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
    //Iteration 4:Rainbow Buttons
   mainStackView.spacing = 1.0
   configureLabelWithText("Hello, Label")
   mainStackView.addArrangedSubview(myLabel)
   rainbowButtons(count: 10)
}    

Build and run using an iPhone 6s Plus.

2016-04-16_10-21-05

The buttons are in an array. We can change them in the array as well. Add this to the ViewController class:

func colorStackView(){
    let subviewCount = mainStackView.arrangedSubviews.count
    let colorIncrement:CGFloat = 1.0 / CGFloat(subviewCount)
    var color:CGFloat = 0.0
    for aView in mainStackView.arrangedSubviews {
        aView.backgroundColor = UIColor(
           hue: color,
           saturation: 1.0,
           brightness: 1.0,
           alpha: 1.0)
        color += colorIncrement
    }
}

We get the array of UIViews from the stack view.  We calculate an increment value so we have an equal number of values between 0.0 and 1.0. We use that value as a color hue for the background of the buttons in a for loop of the elements of the the array. Add the function to the rainbowButtons method.

func rainbowButtons(count count:Int){
    for i in 1...count{
       let titleString = String(format:"Hello Button %i",i)
       let button = makeButtonWithText(titleString)
       mainStackView.addArrangedSubview(button)
    }
    colorStackView()
}

Build and run.

2016-04-16_10-21-06

We get stack view with a different color for each element — even the label since it is the first element of the stack view.

Dynamically Changing the Number of Buttons

We can go one step further: have the number of buttons change by user request. We’ll need an control to increase or decrease the button count. Add a UIStepper to the ViewController class.

var stepper = UIStepper()

Add the following function to configure the stepper

func configureStepper(){
    //Set the attributes of the stepper
    stepper.minimumValue = 1.0
    stepper.maximumValue = 20.0
    stepper.stepValue = 1.0
    stepper.addTarget(self, action: #selector(stepPressed), forControlEvents: .TouchUpInside)
    }

This uses a new selector stepPressed. Add the code for the selector.

func stepPressed(sender:UIStepper){
        let buttonCount = Int(sender.value)
        updateStackView(count: buttonCount)
    }

Our stepper will send a value which we use to set the number of buttons to add to the stack view.
This calls a new method updateStackView. Add that method to your code.

    func updateStackView(count count:Int){
        //clear the stackView Array
        for aView in mainStackView.arrangedSubviews{
            mainStackView.removeArrangedSubview(aView)
            aView.removeFromSuperview()
        }
        //add the stack view back in
        mainStackView.addArrangedSubview(stepper)
        mainStackView.addArrangedSubview(myLabel)
        rainbowButtons(count: count)
    }

Since stack views continue to add items, we clear the stack view first. While adding a view to the stack view also adds the view to the super view, this is not true in reverse. Removing a view from the stack view does not remove the view from the superview. We also remove the view from the superview.

Change our viewDidLoad to this

override func viewDidLoad() {
    super.viewDidLoad()
    //background color for the view
    view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
    //Iteration 5 & 6 dynamic buttons
    mainStackView.spacing = 1.0
    configureLabelWithText("Hello, Label")
    configureStepper()
    updateStackView(count: 1)
}

Build and run. We get one button, a stepper and a label.

2016-04-16_11-14-05

Press the + a few times and you get more buttons.

2016-04-16_11-14-06

Press the a few times and you get less buttons.

2016-04-16_11-14-08

Bonus: Replacing the Stepper with a Nested Stack View

That is most of what you need to know about dynamic controls. The rest is the creative part of using them.  However, I’m not happy with the UI for this app.  The stepper is not the nicest looking control. I’d also like a third button on the stepper to clear the stack view back to 1 button.

To practice with buttons some more, we’ll add three buttons to a horizontal stack view, then nest that in the already existent stack view. If you want more explanation on stack views before doing this, check out my post on programmatic stack views. First we’ll need to declare one more property, a count of our displayed buttons

var buttonCount = 1

We’ll need three buttons that are identical except for their action and title. We’ll make a function to make a button. Add this to the ViewController class code:

func stepperButtonsWithText(text:String,action: Selector ) -> UIButton {
    let button = UIButton()
    button.backgroundColor = UIColor.lightGrayColor()
    button.setTitleColor(UIColor.darkGrayColor(), forState: .Normal)
    button.setTitle(text, forState: .Normal)
    button.addTarget(self,action: action,forControlEvents: .TouchUpInside)
    return button
}

We’ve made light gray buttons with dark gray text. The title and action get set by the parameters. We now use those to create an array of views to stick in a stackview. Add this to the code>ViewController class.

func makeStackViewStepper() -> UIStackView  {
    var viewArray = [UIView]()
    viewArray += [stepperButtonsWithText("Add", 
        action: #selector(addButton))]
    viewArray += [stepperButtonsWithText("Reset",
        action: #selector(resetButton))]
    viewArray += [stepperButtonsWithText("Remove", 
        action: #selector(removeButton))]
}

Then in makeStackViewStepper add the stack view and its properties and return the stack view.

        let stackView = UIStackView(arrangedSubviews: viewArray)
        //properties for the stack view
        stackView.alignment = .Fill
        stackView.distribution = .FillEqually
        stackView.axis = .Horizontal
        stackView.spacing = 1.0
        return stackView
    }

We have not defined the functions for the selectors. Add these three functions to ViewController, just under the stepPressed function.

    func addButton(sender:UIButton){
        buttonCount += 1
        updateStackView(count: buttonCount)
    }
    func resetButton(sender:UIButton){
        buttonCount = 1
        updateStackView(count: buttonCount)
    }
    func removeButton(sender:UIButton){
        if buttonCount > 1 {
            buttonCount -= 1
        }else{
            buttonCount = 1
        }
        updateStackView(count: buttonCount)
    }

These do the same thing as stepPressed, just broken into pieces. We use the property buttonCount to keep track of the number of buttons. We increment, decrement or set back to 1 button, then update the stackview.

Replace the stepper with the stack view in updateStackView. We’ll put the new control at the bottom instead of the top this time.

func updateStackView(count count:Int){
    //clear the stackView Array
    for aView in mainStackView.arrangedSubviews{
         mainStackView.removeArrangedSubview(aView)
         aView.removeFromSuperview()
    }
    //add the stack view back in
    //mainStackView.addArrangedSubview(stepper)
    mainStackView.addArrangedSubview(myLabel)
    rainbowButtons(count: count)
    mainStackView.addArrangedSubview(makeStackViewStepper())
}

Build and run. We get the three new buttons on the bottom.

2016-04-16_12-23-41

Press Add a few tiems, and the stackview increases.

2016-04-16_12-24-10

Press Remove a few time and the stack view decreases.

2016-04-16_12-24-21

Press Reset, and it goes back to one button.

2016-04-16_12-23-41

Rotate and add a few buttons. The controls arrange themselves appropriately.

2016-04-16_12-24-41

The Whole Code

//
//  ViewController.swift
//  SwiftButtonDemo
//
//  Created by Steven Lipton on 4/12/16.
//  Copyright © 2016 MakeAppPie.Com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    //MARK: - Constants, Outlets and Properties
    let image = UIImage(named:"sliceOfAppPie400x400Black1")
    @IBOutlet weak var mainStackView: UIStackView!
    var myLabel = UILabel()
    var stepper = UIStepper()
    var buttonCount = 1
    
    //MARK: - Actions and Selectors
    @IBAction func helloButton(sender:UIButton){
        if myLabel.text !=  sender.titleLabel?.text {
            myLabel.text = sender.titleLabel?.text
        } else {
            myLabel.text = "Hello Pizza"
        }
    }
    func stepPressed(sender:UIStepper){
        let buttonCount = Int(sender.value)
        updateStackView(count: buttonCount)
    }
    
    func addButton(sender:UIButton){
        buttonCount += 1
        updateStackView(count: buttonCount)
    }
    func resetButton(sender:UIButton){
        buttonCount = 1
        updateStackView(count: buttonCount)
    }
    func removeButton(sender:UIButton){
        if buttonCount > 1 {
            buttonCount -= 1
        }else{
            buttonCount = 1
        }
        updateStackView(count: buttonCount)
    }
    

    //MARK: View Making methods
    func makeButtonWithText(text:String) -> UIButton {
        //Initialize a button
        let myButton = UIButton(type: UIButtonType.System)
        //Set a frame for the button. Ignored in AutoLayout/ Stack Views
        myButton.frame = CGRect(x: 30, y: 30, width: 150, height: 150)
        //Set background and tint colors
        myButton.backgroundColor = UIColor.blueColor()
        //State dependent properties title and title color
        myButton.setTitle(text, forState: .Normal)
        myButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        myButton.setTitle("Touched!!", forState: .Highlighted)
        myButton.setTitleColor(UIColor.yellowColor(), forState: .Highlighted)
        //highlighted background image
        myButton.setBackgroundImage(image, forState: .Highlighted)
        myButton.addTarget(self,action: #selector(helloButton),forControlEvents: .TouchUpInside)
        return myButton
    }
    
    func configureLabelWithText(text:String){
        //Set the attributes of the label
        myLabel.frame = CGRect(x: 30, y: 600, width: 150, height: 36)
        myLabel.textColor = UIColor.grayColor()
        myLabel.font = UIFont(name: "Chalkduster", size: 18)
        myLabel.text = text
        myLabel.textAlignment = .Right
    }
    
    func configureStepper(){
        //Set the attributes of the stepper
        stepper.minimumValue = 1.0
        stepper.maximumValue = 20.0
        stepper.stepValue = 1.0
        stepper.addTarget(self, action: #selector(stepPressed), forControlEvents: .TouchUpInside)
    }
    
    func stepperButtonsWithText(text:String,action: Selector ) -> UIButton {
        let button = UIButton()
        button.backgroundColor = UIColor.lightGrayColor()
        button.setTitleColor(UIColor.darkGrayColor(), forState: .Normal)
        button.setTitle(text, forState: .Normal)
        button.addTarget(self,action: action,forControlEvents: .TouchUpInside)
        return button
    }
    
    func makeStackViewStepper() -> UIStackView  {
        var viewArray = [UIView]()
        viewArray += [stepperButtonsWithText("Add", action: #selector(addButton))]
        viewArray += [stepperButtonsWithText("Reset", action: #selector(resetButton))]
        viewArray += [stepperButtonsWithText("Remove", action: #selector(removeButton))]
        let stackView = UIStackView(arrangedSubviews: viewArray)
        //properties for the stack view
        stackView.alignment = .Fill
        stackView.distribution = .FillEqually
        stackView.axis = .Horizontal
        stackView.spacing = 1.0
        return stackView
    }
    
    func rainbowButtons(count count:Int){
        for i in 1...count{
            let titleString = String(format:"Hello Button %i",i)
            let button = makeButtonWithText(titleString)
            mainStackView.addArrangedSubview(button)
        }
        colorStackView()
    }
    
    //MARK: - Instance Methods
    func colorStackView(){
        let subviewCount = mainStackView.arrangedSubviews.count
        let colorIncrement:CGFloat = 1.0 / CGFloat(subviewCount)
        var color:CGFloat = 0.0
        for aView in mainStackView.arrangedSubviews {
            aView.backgroundColor = UIColor(hue: color, saturation: 1.0, brightness: 1.0, alpha: 1.0)
            color += colorIncrement
        }
        
    }
    
    func updateStackView(count count:Int){
        //clear the stackView Array
        for aView in mainStackView.arrangedSubviews{
            mainStackView.removeArrangedSubview(aView)
            aView.removeFromSuperview()
        }
        //add the stack view back in
        //mainStackView.addArrangedSubview(stepper)
        mainStackView.addArrangedSubview(myLabel)
        rainbowButtons(count: count)
        mainStackView.addArrangedSubview(makeStackViewStepper())

    }

    
    //MARK: - Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        //background color for the view
        view.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
        
        /* //Iteration 1: Make a button
        view.addSubview(makeButtonWithText("Indie Button"))
        */
        /*
        //Iteration 2: Make a Button and a label
        view.addSubview(makeButtonWithText("Indie Button"))
        configureLabelWithText("Hello, Label")
        view.addSubview(myLabel)
        */
        /*
        //Iteration 3:Button and label in stack view
        configureLabelWithText("Hello, Label")
        mainStackView.addArrangedSubview(myLabel)
        mainStackView.addArrangedSubview(makeButtonWithText("Hello,Button"))
        mainStackView.addArrangedSubview(makeButtonWithText("Hello,Button 2"))
        mainStackView.addArrangedSubview(makeButtonWithText("Hello,Button 3"))
        */
        /*
        //Iteration 4:Rainbow Buttons
        mainStackView.spacing = 1.0
        configureLabelWithText("Hello, Label")
        mainStackView.addArrangedSubview(myLabel)
        rainbowButtons(count: 10)
        */
        //Iteration 5 & 6 dynamic buttons
        mainStackView.spacing = 1.0
        configureLabelWithText("Hello, Label")
        configureStepper()
        updateStackView(count: 1)
    }
}


2 responses to “How to Make Dynamic UIButtons in Swift”

  1. very nice tutorial!

  2. Thank you. It’s very helpful!!

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.