For my application it was more helpful and performant to create a pattern UIColor
that can be used as a background color.
Once I add this as an extension to UIColor
I can easily put this anywhere in my code and it will always fill perfectly, even as views rotate, shrink and grow!
You use it like this:
view.backgroundColor = UIColor.red.patternStripes()
view.backgroundColor = UIColor.red.patternStripes(color2: .darkGray)
view.backgroundColor = UIColor.red.patternStripes(color2: .darkGray, barThickness: 25.0)
and get this beauty:

Here is an extension to UIColor:
extension UIColor {
/// make a diagonal striped pattern
func patternStripes(color2: UIColor = .white, barThickness t: CGFloat = 25.0) -> UIColor {
let dim: CGFloat = t * 2.0 * sqrt(2.0)
let img = UIGraphicsImageRenderer(size: .init(width: dim, height: dim)).image { context in
// rotate the context and shift up
context.cgContext.rotate(by: CGFloat.pi / 4.0)
context.cgContext.translateBy(x: 0.0, y: -2.0 * t)
let bars: [(UIColor,UIBezierPath)] = [
(self, UIBezierPath(rect: .init(x: 0.0, y: 0.0, width: dim * 2.0, height: t))),
(color2,UIBezierPath(rect: .init(x: 0.0, y: t, width: dim * 2.0, height: t)))
]
bars.forEach { $0.0.setFill(); $0.1.fill() }
// move down and paint again
context.cgContext.translateBy(x: 0.0, y: 2.0 * t)
bars.forEach { $0.0.setFill(); $0.1.fill() }
}
return UIColor(patternImage: img)
}
}
Basically, I am creating a temporary drawing space for one little rectangle to paint. I paint it with a pattern that will match seamlessly on all sides when repeated. Then I snap an image of this and tell UIColor
to use it as a pattern.
The trick I that you have to make your pattern image big enough to paint each bar two times. That turns out to be bar thickness * 2 * sqrt(2).
I know I could get beaten up a little about style. Here are my thoughts:
- I used one letter variables like
t
, which is not very descriptive. My defense: I think it makes the equations more readable and feel like it's okay when it's limited to only the next few lines.
- Tuples. Same as #1
- Using decimals (
4.0
instead of just 4
). I would prefer to not use the decimals but I have found better compile times with the decimal. On bigger projects it can make a huge difference. I will also admit that it may not read as pretty but being less ambiguous about type can even be helpful to humans.
3 Colors:
I just realized that the original question was asking for 3 colors, so here is a version for that...
First, the math:

Updated code:
extension UIColor {
/// make a diagonal striped pattern
func pattern3Stripes(color2: UIColor, color3: UIColor, barThickness t: CGFloat = 25.0) -> UIColor {
let sqrt2: CGFloat = sqrt(2.0)
let dim: CGFloat = t * 3.0 * sqrt2
let size: CGSize = .init(width: dim, height: dim)
let img = UIGraphicsImageRenderer(size: size).image { context in
// rotate the context and shift up
context.cgContext.rotate(by: CGFloat.pi / 4.0)
context.cgContext.translateBy(x: 0.0, y: -3.0 * t)
let bars: [(UIColor,UIBezierPath)] = [
(self, UIBezierPath(rect: .init(x: 0.0, y: 0.0, width: dim * sqrt2, height: t))),
(color2,UIBezierPath(rect: .init(x: 0.0, y: t, width: dim * sqrt2, height: t))),
(color3,UIBezierPath(rect: .init(x: 0.0, y: 2.0 * t, width: dim * sqrt2, height: t)))
]
bars.forEach { $0.0.setFill(); $0.1.fill() }
// move down and paint again
context.cgContext.translateBy(x: 0.0, y: 3.0 * t)
bars.forEach { $0.0.setFill(); $0.1.fill() }
}
return UIColor(patternImage: img)
}
}
Usage:
view.backgroundColor = UIColor.green.pattern3Stripes(color2: .white, color3: .red, barThickness: 25.0)
Result:
