Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fill a UIView with diagonally drawn lines?

How to fill a UIView like this (with some diagonally drawn white lines).

enter image description here

PS: My intentions is about the fill not the border.

Any help?

like image 773
Goppinath Avatar asked Mar 02 '16 14:03

Goppinath


1 Answers

One way of achieving this would be to override the draw(_:) method of UIView and do your custom drawing there.

Drawing diagonal lines is fairly simple, you just need to:

  • Stride from 0 to width + height (along the horizontal edge of the rect, then up the vertical), by the gap + line width, converted from being a diagonal (at 45º) length to being parallel to the edge of the rect to draw in.

  • At each iteration, draw a line from the given point for that iteration to the point on the edge opposite (at 45º). We get this point by simply working up the vertical edge of the rect, then along the horizontal)

Something like this should achieve the desired result:

class StripeyView : UIView {

    let lineGap: CGFloat = 7
    let lineWidth: CGFloat = 3
    let lineColor = UIColor.white

    override func draw(_ rect: CGRect) {

        let ctx = UIGraphicsGetCurrentContext()!

        // flip y-axis of context, so (0,0) is the bottom left of the context
        ctx.scaleBy(x: 1, y: -1)
        ctx.translateBy(x: 0, y: -bounds.size.height)

        // generate a slightly larger rect than the view,
        // to allow the lines to appear seamless
        let renderRect = bounds.insetBy(dx: -lineWidth * 0.5, dy: -lineWidth * 0.5)

        // the total distance to travel when looping (each line starts at a point that
        // starts at (0,0) and ends up at (width, height)).
        let totalDistance = renderRect.size.width + renderRect.size.height

        // loop through distances in the range 0 ... totalDistance
        for distance in stride(from: 0, through: totalDistance,
                               // divide by cos(45º) to convert from diagonal length
                               by: (lineGap + lineWidth) / cos(.pi / 4)) {

            // the start of one of the stripes
            ctx.move(to: CGPoint(
                // x-coordinate based on whether the distance is less than the width of the
                // rect (it should be fixed if it is above, and moving if it is below)
                x: distance < renderRect.width ?
                    renderRect.origin.x + distance :
                    renderRect.origin.x + renderRect.width,

                // y-coordinate based on whether the distance is less than the width of the
                // rect (it should be moving if it is above, and fixed if below)
                y: distance < renderRect.width ?
                    renderRect.origin.y :
                    distance - (renderRect.width - renderRect.origin.x)
            ))

            // the end of one of the stripes
            ctx.addLine(to: CGPoint(
                // x-coordinate based on whether the distance is less than the height of
                // the rect (it should be moving if it is above, and fixed if it is below)
                x: distance < renderRect.height ?
                    renderRect.origin.x :
                    distance - (renderRect.height - renderRect.origin.y),

                // y-coordinate based on whether the distance is less than the height of
                // the rect (it should be fixed if it is above, and moving if it is below)
                y: distance < renderRect.height ?
                    renderRect.origin.y + distance :
                    renderRect.origin.y + renderRect.height
            ))
        }

        // stroke all of the lines added
        ctx.setStrokeColor(lineColor.cgColor)
        ctx.setLineWidth(lineWidth)
        ctx.strokePath()
    }
}

Output:

enter image description here

(Assuming the view has a red backgroundColor)

You can adjust the lineGap and lineWidth properties to generate varying results.

like image 198
Hamish Avatar answered Nov 15 '22 20:11

Hamish