Ever wanted that color but a bit darker? Or to combine one color with another?
That’s what we’ll learn to do now
What is color to a computer?
The color of a pixel is described by the amount of red, green and blue light it emits.
In case you didn’t already know there are thousands of tiny colored lights/LEDs on the screen you are using to read this article. Under a microscope your screen looks like this:
The computer only knows how much electricity to give to each one of the 3 LEDs that represent a pixel. So if a pixel is red the green and blue lights get low or no electricity and the red one gets a lot.
RGB Color Model
The RGB color model (stands for Red Green Blue) is an additive color model in which red, green and blue light are added together in various ways to reproduce a broad spectrum of colors.
You might remember from school that red, blue and yellow are primary colors. And that is still true!
But there are two different things:
1) how colors combine if they reflect light
2) how colors combine if they emit light
When you use paint light either from the sun or from another source hits the paint and then reflcts in to your eyes. When you use pixels on a screen light is emitted from the screen and then hits your retina
To encode a color in RGB you need three numebrs between 0
and 255
or between 0.0
and 1.0
. If you use the floating point representation it will still get converted to the discrete representation from 0
to 255
where 0
means the light is not turned on for that color and 255
that it’s turned on at the maximum level.
One thing to keep in mind is that any display only shows colors in RGB.
RGBA Color Space
RGBA(stands for red greeb blue alpha) extends the RGB color model with an extra layer of information for opacity. This is the color we actually use in our software. But if the screen does not have a alpha LED, what does it do with that information?
The alpha channel describes how much light can pass trough. So if the opacity is set to 100%
the color will get shown on the screen exactly as the RGB part of the model describes it. If alpha is 0%
then the pixel is fully transparent.
3 circles – each one has a primary color and
50%
opacity.
The inventors named alpha after the Greek letter in the classic linear interpolation formula (1 - α) * A + α * B
.
Let’s turn some lights on!
In iOS colors are represented by the UIColor
class. To create a new color you have to pass the values of the color components encoded as the floating points:
let color = UIColor(red: 1, green: 0.5, blue: 1, alpha: 1)
That will give this pinkish color:
Making all values 1
will give white. And if you make the rgb part 0
and alpha 1
you get black.
How to combine colors?
A simple way to combine colors is by using the linear interpolation formula mentioned before:
func lerp(from a: CGFloat, to b: CGFloat, alpha: CGFloat) -> CGFloat {
return (1 - alpha) * a + alpha * b
}
lerp
stands for linear interpolation and is the usual name this function is given. If you ever seen some code where there was a lot of lerping now you know what that means
If you want to learn more about linear interpolation you can try the lessons from Khan Academy or if you are lazy like me you can watch this amazing talk by Steven Wittens – he has more cool videos on his website:
Let’s lerp some colors:
The first thing we need to do is get the color components back from a UIColor
unfortunately there are no red
, green
, blue
, alpha
properties:
extension UIColor {
func components() -> (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
getRed(&r, green: &g, blue: &b, alpha: &a)
return (r, g, b, a)
}
}
Now we can lerp colors:
extension UIColor {
...
func combine(with color: UIColor, amount: CGFloat) -> UIColor {
let fromComponents = components()
let toComponents = color.components()
let redAmount = lerp(from: fromComponents.red,
to: toComponents.red,
alpha: amount)
let greenAmount = lerp(from: fromComponents.green,
to: toComponents.green,
alpha: amount)
let blueAmount = lerp(from: fromComponents.blue,
to: toComponents.blue,
alpha: amount)
let color = UIColor(red: redAmount,
green: greenAmount,
blue: blueAmount,
alpha: 1)
return color
}
}
To make a lighter shade of that pink we made before we can call:
color.combine(with: .white, amount: 0.2)
Before | After |
---|---|
![]() | ![]() |
OK, now let’s have some fun with what we’ve learned!
Let’s make a color picker that also show lighter and darker shades so we can browse the color space more efficiently:
Step 1: Create a new Playground
Open Xcode and create a new Playground, set the platform to iOS.
Step 2: Create a View Controller
Create a subclass of UIViewController
and initialize it’s view with:
class ViewController: UIViewController {
override func loadView() {
let width: CGFloat = 300
let height: CGFloat = 500
let screenSize = CGSize(width: width,
height: height)
let frame =
CGRect(origin: .zero,
size: screenSize)
view = UIView(frame: frame)
view.backgroundColor = .white
}
}
Step 3: Show the view in the Playground
The first thing we need to do is to import the PlaygroundSupport
module:
import PlaygroundSupport
class ColorPicker: UIViewController {
...
}
Create a instance of ColorPicker
let colorPicker = ColorPicker()
Set it as the liveView
of the current Playground page:
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = colorPicker.view
Open the Assistand Editor by pressing Command
+ Option
+ Return
(⌘
+ ⌥
+ ↩
). You should be able to see a white rectangle in the right side of the playground window.
Step 4: Basic UI
We need one sliders for each color component:
class ColorPicker: UIViewController {
var redSlider: UISlider!
var greenSlider: UISlider!
var blueSlider: UISlider!
func loadView() {
...
let sliderSize =
CGSize(width: width - 2 * padding,
height: 30)
let redSliderFrame =
CGRect(origin: CGPoint(x: padding, y: 300),
size: sliderSize)
redSlider = UISlider(frame: redSliderFrame)
redSlider.addTarget(self,
action: #selector(didMoveSlider(_:)),
for: .valueChanged)
view.addSubview(redSlider)
let greenSliderFrame =
CGRect(origin: CGPoint(x: padding, y: 340),
size: sliderSize)
greenSlider = UISlider(frame: greenSliderFrame)
greenSlider.addTarget(self,
action: #selector(didMoveSlider(_:)),
for: .valueChanged)
view.addSubview(greenSlider)
let blueSliderFrame =
CGRect(origin: CGPoint(x: padding, y: 380),
size: sliderSize)
blueSlider = UISlider(frame: blueSliderFrame)
blueSlider.addTarget(self,
action: #selector(didMoveSlider(_:)),
for: .valueChanged)
view.addSubview(blueSlider)
}
func didMoveSlider(_ slider: UISlider) {
}
}
Note that all sliders call the didMoveSlider(_:)
method when their value changes. That’s because we have to do the same thing if any of them changes – update the color on the screen.
And if we mentioned that let’s make a view to display our color:
class ColorPicker: UIViewController {
...
var colorView: UIView!
func loadView() {
...
let colorViewFrame = CGRect(x: padding, y: padding, width: width - 2 * padding, height: width - 2 * padding)
colorView = UIView(frame: colorViewFrame)
colorView.backgroundColor = .white
colorView.addBorder()
}
}
The last line ads a border around the view so we can see the view even if it’s white.
extension UIView {
func addBorder() {
layer.borderWidth = 0.5
}
}
At this point the UI should look like this:
Step 5: Update the color
class ColorPicker: UIViewController {
...
func updateColor() {
let redAmount = CGFloat(redSlider.value)
let greenAmount = CGFloat(greenSlider.value)
let blueAmount = CGFloat(blueSlider.value)
let color = UIColor(red: redAmount,
green: greenAmount,
blue: blueAmount,
alpha: 1)
colorView.backgroundColor = color
}
func didMoveSlider(_ slider: UISlider) {
updateColor()
}
}
colorView
should update when you move a slider:
Step 6: Show shades
class ColorPicker: UIViewController {
...
let shadesCount = 10
var lightShades: [UIView] = []
var darkShades: [UIView] = []
override func loadView() {
...
let totalWidth = width - 2 * padding
let shadeSize = totalWidth / CGFloat(shadesCount)
for i in 0..<shadesCount {
// light shade
let lightShadeFrame = CGRect(x: padding + CGFloat(i) * shadeSize,
y: 430,
width: shadeSize,
height: shadeSize)
let lightShade = UIView(frame: lightShadeFrame)
lightShade.backgroundColor = .white
lightShade.addBorder()
lightShades.append(lightShade)
view.addSubview(lightShade)
// dark shade
let darkShadeFrame = CGRect(x: padding + CGFloat(i) * shadeSize,
y: 430 + shadeSize,
width: shadeSize,
height: shadeSize)
let darkShade = UIView(frame: darkShadeFrame)
darkShade.backgroundColor = .white
darkShade.addBorder()
darkShades.append(darkShade)
view.addSubview(darkShade)
}
}
}
Update shades when the color changes:
class ColorPicker: UIViewController {
...
func updateColor() {
let redAmount = CGFloat(redSlider.value)
let greenAmount = CGFloat(greenSlider.value)
let blueAmount = CGFloat(blueSlider.value)
let color = UIColor(red: redAmount,
green: greenAmount,
blue: blueAmount,
alpha: 1)
colorView.backgroundColor = color
for i in 0..<shadesCount {
let t = CGFloat(i) / CGFloat(shadesCount)
let lightShade = lightShades[i]
lightShade.backgroundColor =
color.combine(with: .white, amount: t)
let darkShade = darkShades[i]
darkShade.backgroundColor =
color.combine(with: .black, amount: t)
}
}
}
Step 7: Initalize Sliders
Set the value of each slider to 0.5
so we can test if the shades are displayed correctly:
class ColorPicker: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
redSlider.value = 0.5
greenSlider.value = 0.5
blueSlider.value = 0.5
updateColor()
}
}
The screen should look like this:
Step 8: A finishing touch
Set the background color of the ColorPicker
to a really white version of the selected color:
class ColorPicker: UIViewController {
...
func updateColor() {
...
view.backgroundColor =
color.combine(with: .white, amount: 0.9)
}
}
Download the complete Playground
Exercises
- Add two buttons. When you tap on one it should copy the current color. Add another view that shows color you get by adding equal amounts of the first and second button color
- Instead of just one view for
0.5
amount show a list similar to how we show shades. - Show all colors on hex grid
Conclusion
It’s easy and fun to create and combine colors and with a bit of common sence you can make pretty stuff
Hope you enjoyed this article! Please share and subscribe for more!