# Amazingly simple to do if you know the natty algorithm:
class Ruled: UIView {
override func draw(_ rect: CGRect) {
let T: CGFloat = 15 // desired thickness of lines
let G: CGFloat = 30 // desired gap between lines
let W = rect.size.width
let H = rect.size.height
guard let c = UIGraphicsGetCurrentContext() else { return }
c.setStrokeColor(UIColor.orange.cgColor)
c.setLineWidth(T)
var p = -(W > H ? W : H) - T
while p <= W {
c.move( to: CGPoint(x: p-T, y: -T) )
c.addLine( to: CGPoint(x: p+T+H, y: T+H) )
c.strokePath()
p += G + T + T
}
}
}
[![enter image description here][1]][1]
[1]: https://i.sstatic.net/GsI5T5tQ.png
## Amazingly simple algorithm ...
Say you have these values:
let T: CGFloat = 15 // desired thickness of lines
let G: CGFloat = 30 // desired gap between lines
let W = rect.size.width
let H = rect.size.height
Remarkably, it is this simple ...
var p = -(W > H ? W : H) - T
while p <= W {
c.move( to: CGPoint(x: p-T, y: -T) )
c.addLine( to: CGPoint(x: p+T+H, y: T+H) )
c.strokePath()
p += G + T + T
}
[![enter image description here][1]][1]
Here is a complete UIView class:
class Ruled: UIView {
override func draw(_ rect: CGRect) {
let T: CGFloat = 15 // desired thickness of lines
let G: CGFloat = 30 // desired gap between lines
let W = rect.size.width
let H = rect.size.height
guard let c = UIGraphicsGetCurrentContext() else { return }
c.setStrokeColor(UIColor.orange.cgColor)
c.setLineWidth(T)
var p = -(W > H ? W : H) - T
while p <= W {
c.move( to: CGPoint(x: p-T, y: -T) )
c.addLine( to: CGPoint(x: p+T+H, y: T+H) )
c.strokePath()
p += G + T + T
}
}
}
That's it !
The entire fundamental algorithm:
## 1. Start at the top-left, *minus the longest side*
## 2. Draw diagonals until you come to the right
Nice and easy! :)
--------
## To clip to a rectangle:
The class above simply draws one "box" the size of the UIView.
Often, you want to draw many of the "boxes" within one view, at different positions. A typical example is for a calendar.
[![enter image description here][2]][2]
This example will draw one box. Call it for each of the boxes you need to draw:
Furthermore, this example explicitly draws both stripes, rather than drawing one stripe over the background color:
func simpleStripes(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
let stripeWidth: CGFloat = 20.0 // whatever you want
let m = stripeWidth / 2.0
guard let c = UIGraphicsGetCurrentContext() else { return }
c.setLineWidth(stripeWidth)
let r = CGRect(x: x, y: y, width: width, height: height)
let longerSide = width > height ? width : height
c.saveGState()
c.clip(to: r)
var p = x - longerSide
while p <= x + width {
c.setStrokeColor(pale blue)
c.move( to: CGPoint(x: p-m, y: y-m) )
c.addLine( to: CGPoint(x: p+m+height, y: y+m+height) )
c.strokePath()
p += stripeWidth
c.setStrokeColor(pale gray)
c.move( to: CGPoint(x: p-m, y: y-m) )
c.addLine( to: CGPoint(x: p+m+height, y: y+m+height) )
c.strokePath()
p += stripeWidth
}
c.restoreGState()
}
--------
## If you want to animate them moving...
1, To offset, simply subtract from the pointer when you start it. Amazingly, nothing else needs to be changed.
var p = x - longerSide - offset // animate offset from 0 to stripeWidth
2, Careful programmers would prefer an offset **equal to the miter** to avoid the "pointy top-left corner" problem:
var p = x - longerSide - offset - m // for better-looking top-left corner
[![enter image description here][3]][3]
3, You can use **any number of stripes** in various colors, and indeed you can use **different stripe widths** in any combination. Amazingly, the algorithm still works and is safe. (If you have more than one width, just set the miter `m` as the maximum width.)
[1]: https://i.sstatic.net/C1DaE.png
[2]: https://i.sstatic.net/QBLEL.png
[3]: https://i.sstatic.net/ldLqQ.png