Make App Pie

Training for Developers and Artists

Make A Toggle Button

Sometimes you need a control that doesn’t yet exist. For example, the UISwitch control is far from customizable. I’d like a toggle switch that looks more like an old-fashioned switch or pushbutton. Let’s learn the basics of making your own controls by making a UIButton into a toggle button.
Open the example file. You’ll find an empty class UIToggleButton. in the UIToggleButton.swift file. To make our toggle button I’m going to subclass UIButton, since much of what I want is there.

 class UIToggleButton:UIButton{
}

I can’t use an extension because I’m going to add more properties to the button. The most important of those will be isOn.

var isOn:Bool = false

UIButton subclasses UIControl. There is a series of tracking methods in UIControl that handles touches. For controls, you don’t use UIResponder for touch events, but these methods instead. The control will handle any target-action pairs in the class hierarchy. I’ll change the button when I stop tracking a touch using the endTracking method.

override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
}

Always call super when you use these methods.

super.endTracking(touch, with: event)

And I’ll change the state of the isOn button.

isOn = !isOn 

Head to the ViewController code. You’ll see I made a button configuration method configureToggleButton. One problem with custom controls like this is you will have to add them programmatically without more work, which I’ll cover in a future tip. I added two methods to configure the button and to lay out the button, which you can find in the example file or the listing below. I’ll use the button in the action I set up, where I’ll change the title on the toggle. This way you can see the action and the touch event can run independently, but see the effect of the touch event on the toggle.

if sender.isOn {
            sender.setTitle("On", for: .normal)
        } else {
            sender.setTitle("Off", for: .normal)
        }

Build and run. You’ll have a button in the center of the screen.

You can add more features. I’ll add images for the buttons.
I may not use an image. If I don’t I’ll want the image to be nil, and use the superclass properties, so I’ll use optionals for the image in the UIToggleButtonClass

public var onImage:UIImage! = nil 
public var offImage:UIImage! = nil

In my UIToggleButton method,  II’ll make a method updateDisplay which will change the button’s background image.

func updateDisplay() {
        if isOn {
            if let onImage = onImage{
                setBackgroundImage(onImage, for: .normal)
            }
        } else {
            if let offImage = offImage{
                setBackgroundImage(offImage, for: .normal)
            }
        }
    }

I’ll update the display once I set the image. I’ll use a property setter to do that.

var isOn:Bool = false{
    didSet{
       updateDisplay()
    }
}

I’ll do the same for the off image, so I’ll copy and paste that

var offImage:UIImage! = nil {
    didSet{
      updateDisplay()
    }
}

And the same for the on Image

var onImage:UIImage! = nil{
    didSet{
       updateDisplay()
    }
}

I added to the assets folder a toggle off and toggle on button image. Head to the ViewController. In the cofigureToggleButton, add two more lines of code.

 
toggleButton.offImage = UIImage(named: "Toggle off")
 toggleButton.onImage = UIImage(named:"Toggle on")

Build and run. Tap the button. You’ll get a cool looking button that glows when on, and dims when off.

You’ll find a few more examples of switches and toggles you can use in the downloads file. Give them a try like this switch

This is only scratching the surface of this subclass. You can add background colors the same way as images. You could add haptics to make the user feel the click of the button. You might also want to play with making some properties and methods public and private. Play around and see what else you can do.

The Whole Code

UIToggleButton.swift

//
//  UIToggleButton.swift
//  Toggle buttons and switches
//
//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//

import UIKit

class UIToggleButton:UIButton{
    var isOn:Bool = false{
        didSet{
            updateDisplay()
        }
    }
    var onImage:UIImage! = nil{
        didSet{
            updateDisplay()
        }
    }
    var offImage:UIImage! = nil{
        didSet{
            updateDisplay()
        }
    }
    
    func updateDisplay(){
        if isOn {
            if let onImage = onImage{
                setBackgroundImage(onImage, for: .normal)
            }
        } else {
            if let offImage = offImage{
                setBackgroundImage(offImage, for: .normal)
            }
        }
    }
    override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
        super.endTracking(touch, with: event)
        isOn = !isOn
    }
}

ViewController.swift

//
//  ViewController.swift
//  Toggle buttons and switches
//
//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//

import UIKit



class ViewController: UIViewController {
    @IBOutlet weak var basicSwitch: UISwitch!
    
   
    var toggleButton: UIToggleButton!
    
    //Action when button recieves touchUpInside
    @IBAction func didToggleButton(_ sender: UIToggleButton) {
        if sender.isOn {
            sender.setTitle("ON", for: .normal)
        } else {
            sender.setTitle("OFF", for: .normal)
        }
    }
    
    //Configure the toggle button for this app.
    func configureToggleButton()-> UIToggleButton{
        let toggleButton = UIToggleButton()
        toggleButton.offImage = UIImage(named: "Toggle off")
        toggleButton.onImage = UIImage(named: "Toggle on")
        toggleButton.setTitleColor(.black, for: .normal)
        toggleButton.titleLabel?.font = UIFont(name: "Gill Sans", size: 36)
        toggleButton.setTitle("OFF", for: .normal)
        toggleButton.addTarget(self, action: #selector(didToggleButton(_:)), for: .touchUpInside)
        return toggleButton
    }
    
    //Add the button to the layout centered on the view.
    func addToggleButton(to view:UIView) {
        toggleButton = configureToggleButton()
        view.addSubview(toggleButton)
        toggleButton.translatesAutoresizingMaskIntoConstraints = false
        var constraints = [NSLayoutConstraint]()
        constraints += [NSLayoutConstraint.init(item: toggleButton, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerXWithinMargins, multiplier: 1.0, constant: 0)]
         constraints += [NSLayoutConstraint.init(item: toggleButton, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerYWithinMargins, multiplier: 1.0, constant: 0)]
         constraints += [NSLayoutConstraint.init(item: toggleButton, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 128)]
        constraints += [NSLayoutConstraint.init(item: toggleButton, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 96)]
        NSLayoutConstraint.activate(constraints)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        addToggleButton(to: view)
    }
}


2 responses to “Make A Toggle Button”

  1. How come you create you create your own property, isOn, instead of using the already built in isSelected?

    1. Two reasons: For this tutorial where I want to explain everything, I like to make my own states so they are very visible and “close to the chest”, compared to a property of a superclass. I didn’t here, but in many cases I’d also make the isOn private so the button cannot have its state changed externally.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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

%d bloggers like this: