Bees & Bombs
Rebuilding a gif from Bees & Bombs
Author
Oliver Andrews (with a little ❤ from Travis)
Estimated Time
10 - 20 minutes
Travis recently hacked UISwitch
to make customizing standard UIKit switches easy and straightforward. I had this really cool switch example in mind that I found on this pintrest board, and then jammed with Jake from @jakesmakes on the design and layout of our own version of that switch.
The Switch
consists of two components: The switch background and the switch button. In this tutorial, I’ll show you how to add the Switch to your WorkSpace
, customize the components, and then make sure everything looks good.
If you haven’t already done so, install C4 by following the instructions on our install tutorial. The easiest is to use the first option.
In the following steps you’ll lay the groundwork for creating a custom version of a UISwitch
. To make things a bit smoother you’ll have to incorporate some already made files. First…
Create a new C4 Project
You’ll be using 3 classes that were discussed in a previous tutorial.
Grab a copy of the 3 files found HERE.
The files you’ve just grabbed consist of a Switch
, SwitchThumb
and SwitchBackground
.
Drag them into the file inspector of your project.
In the WorkSpace
file add this line of code in setup()
:
1
2
var switch = Switch(thumb: SwitchThumb(), background: SwitchBackground())
canvas.add(switch)
When you run it, you should see the switch with its default colors.
You’re going to need some assets that we’ve already prepared.
After unzipping the file grab all of the assets and drag them into the Images.xcassets
folder in your project, like so:
To create your own custom version switch your going to create a subclass of Switch
which is already a subclass UISwitch
. The Switch
class has two major components:
To create the moon version, you’ll be subclassing these three objects:
Let’s start with the background.
The SwitchBackground
is a subclass of View
that allows us to customize the pill behind the thumbnail button.
Create a new file and name it MoonBackground
then add the following code to it:
1
2
3
4
5
6
7
8
9
class MoonBackground: SwitchBackground {
var sunColor = Color(red: 164, green: 245, blue: 253, alpha: 1.0)
var moonColor = Color(red: 19, green: 44, blue: 72, alpha: 1.0)
override func setup() {
self.backgroundColor = sunColor
}
}
Here you’re making a new class, a subclass of SwitchBackground
and then adding two colors as variables. You’ll create a way to switch the colors soon, but for now, just set the backgroundColor
to sunColor
in setup()
, like this:
1
2
3
override func setup() {
self.backgroundColor = sunColor
}
You want the backgroundColor
to change when the switch is pressed, so you’ll need to override the on()
and off()
functions.
1
2
3
4
5
6
7
override func on() {
self.backgroundColor = moonColor
}
override func off() {
self.backgroundColor = sunColor
}
All that’s left for this class is to create some functions to place all the stars. Below your two other class variables add this:
1
var stars = [Image]()
Then add the following function, which will place all of the small stars and add them to your star’s array.
1
2
3
4
5
6
7
8
9
func placeSmallStars() {
let centers = [Point(21.0,5.75), Point(6.5,10.25), Point(20.5,20.75), Point(17.0,26.5), Point(18.0,13.0), Point(17.0,7.75)]
for point in centers {
let smallStar = Image("StarSmall")!
smallStar.center = point
stars.append(smallStar)
self.add(smallStar)
}
}
Just like the small stars, you’ll need a function to add all of the large stars.
1
2
3
4
5
6
7
8
9
func placeLargeStars() {
let centers = [Point(9.5, 18.5), Point(12.0, 13.0), Point(17.0, 27.25)]
for point in centers {
let largeStar = Image("StarLarge")!
largeStar.center = point
stars.append(largeStar)
self.add(largeStar)
}
}
Remember to call both of these methods from
setup()
Customizing the thumbnail is a lot like the last section.
Create a new file called MoonThumb.swift
and add the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import UIKit
class MoonThumb: SwitchThumb {
var moonTexture = Image("MoonTexture")
var outerGlow = Image("OuterGlow")
var sunColor = Color(red: 255, green: 238, blue: 90, alpha: 1.0)
var moonColor = Color(red: 251, green: 246, blue: 217, alpha: 1.0)
override func setup() {
lineWidth = 0
fillColor = sunColor
self.add(moonTexture)
outerGlow?.constrainsProportions = true
outerGlow?.center = self.bounds.center
self.add(outerGlow)
}
}
This snippet sets up the basic elements for the MoonThumb
class. It does the following:
Since the assets for the thumbnail are already the proper size, we don’t neet to change their widths or frames.
Override the on()
and off()
super class functions so they look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
override func on() {
fillColor = moonColor
moonTexture?.opacity = 0.66
moonTexture?.transform.rotate(-M_PI_4)
outerGlow?.opacity = 1.0
}
override func off() {
fillColor = sunColor
moonTexture?.opacity = 0.0
moonTexture?.transform.rotate(M_PI_4)
outerGlow?.opacity = 0.0
}
When triggering the switch, we want to see the moon “roll” into position. This is why we toggle its rotation between
-M_PI_4
andM_PI_4
.
In order to get your switch to use your newly made components you’ll need to subclass Switch
.
Create a new file and call it MoonSwitch.swift
and add the following code:
1
2
3
4
5
6
7
8
9
10
class MoonSwitch: Switch {
override func awakeFromNib() {
self.thumb = MoonThumb()
self.background = MoonBackground()
replaceViews()
setup()
toggle()
}
}
At this point, you should be able to see you new switch when your app runs if you go back to your project’s WorkSpace
and change it to this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import UIKit
class WorkSpace: CanvasController {
var dayColor = Color(red: 122, green: 232, blue: 252, alpha: 1.0)
var nightColor = Color(red: 12, green: 30, blue: 50, alpha: 1.0)
var myswitch: MoonSwitch!
override func setup() {
myswitch = MoonSwitch(thumb: MoonThumb(), background: MoonBackground())
canvas.add(myswitch)
myswitch.center = canvas.view.center
myswitch.addTarget(self, action: "toggle", forControlEvents: UIControlEvents.ValueChanged)
toggle()
}
func toggle() {
ViewAnimation(duration: 0.25) {
self.canvas.backgroundColor = self.myswitch.on == true ? self.nightColor : self.dayColor
}.animate()
}
}
A couple things you should notice here:
myswitch.addTarget(...)
is the line of code that syncs up the UISwitch
action with the toggle method. Attaching this action here doesn’t preclude you from attaching more actions in Interface Builder.self.myswitch.on == true ? self.nightColor : self.dayColor
is a simple technique for using a ternary conditional ?
to switch between different colors.At this point, the only thing missing from your switch is the clouds. Let’s get them in there! Add the following class variables:
1
2
3
var clouds = [Image]()
let cloudOpacities = [[0.83,0.15],[0.58,0.28],[0.52,0.07]]
let cloudTargets = [[Point(17.0, 28.5),Point(27.0, 28.5)],[Point(15.775, 4.0),Point(21.0, 9.0)],[Point(43.5, 20.5),Point(5.0, 20.5)]]
Now override the superclass function setup()
and in this function initialize a view to add your clouds to and a shape to use as a mask. With a for loop you can create the clouds and add them to the view you just made.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
override func setup() {
let cloudsView = View(frame: Rect(self.bounds))
cloudsView.interactionEnabled = false
let mask = Rectangle(frame: Rect(self.bounds))
mask.lineWidth = 0
mask.corner = Size(mask.height/2,mask.height/2)
cloudsView.mask = mask
for i in 0...2 {
let image = Image("Cloud\(i)")!
image.center = cloudTargets[i][Int(on)]
image.opacity = cloudOpacities[i][Int(on)]
clouds.append(image)
cloudsView.add(image)
}
clouds[1].transform.scale(0.5,0.5)
self.add(cloudsView)
thumb?.toggle(on)
background?.toggle(on)
}
We want the clouds to be masked, but have the glow of the moon bleed over the edge of the switch. To get both effects it’s best to contain the clouds to their own view. This is why we add them to a view and then mask that view.
In setup()
set your thumb and background toggle to on; and while you’re at it, override toggle on this class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
override func toggle() {
super.toggle()
let a = ViewAnimation(duration: 0.25) {
for i in 0..<self.clouds.count {
self.clouds[i].opacity = self.cloudOpacities[i][Int(self.on)]
self.clouds[i].center = self.cloudTargets[i][Int(self.on)]
}
let scale = self.on == true ? 2.0 : 0.5
self.clouds[1].transform.scale(scale,scale)
}
a.curve = .EaseOut
a.animate()
}
Now, whenever your switch is pressed you should see your clouds move and change opacities.
The
cloudOpacities
andcloudTargets
arrays each have three elements(for each cloud) and each element is an array of two elements(for each state). The toggle state boolean is converted to an integer,Int(self.on)
, so that it can be is used to ensure the correct state is accessed.
##That’s It.
You’ve just added your own personalized touch to an actual UISwitch
object. Though it looks different, it acts just the same as its native counterpart. The best part is that you can drop this object right into any other iOS app, and even work with it from Interface Builder.
###Code You can grab a copy of the code for this project from HERE
That’s it! Try switching out the images and colors we used in this tutorial to create your own custom UISwitch
. Just subclass the components of Switch
, add your own style and initialize.
To see the final version of this example