Search code examples
swiftswift2core-graphicsuibezierpathswift3

Calculation of stroke property 'Dash' in dashed circle - Swift


I'm developing an app. I haven't completed my apprenticeship of Swift 2.2/3.0 and I'm in search of some answers.

First: I am using PaintCode to generate the start of Swift code. I made a drawing with the following properties:

enter image description here

Code Swift:

func drawSpeedView(strokeGap strokeGap: CGFloat = 30, strokeDash: CGFloat = 4, strokePhase: CGFloat = 0, strokeWidth: CGFloat = 31, strokeStartAngle: CGFloat = 225, strokeEndAngle: CGFloat = 315) {
    //// General Declarations
    let context = UIGraphicsGetCurrentContext()

    //// DashedLarge Drawing
    let dashedLargeRect = CGRect(x: 14.5, y: 17.5, width: 291, height: 291)
    let dashedLargePath = UIBezierPath()
    dashedLargePath.addArcWithCenter(CGPoint(x: dashedLargeRect.midX, y: dashedLargeRect.midY), radius: dashedLargeRect.width / 2, startAngle: -strokeStartAngle * CGFloat(M_PI)/180, endAngle: -strokeEndAngle * CGFloat(M_PI)/180, clockwise: true)

    UIColor.blackColor().setStroke()
    dashedLargePath.lineWidth = strokeWidth
    CGContextSaveGState(context)
    CGContextSetLineDash(context, strokePhase, [strokeDash, strokeGap], 2)
    dashedLargePath.stroke()
    CGContextRestoreGState(context)
}

My problem: This code is optimized for iPhone 5. For the proportion of dotted numbers, I need to create a calculation for the value of strokeDash for iPhone 6/6s and 6+/6s+

What I need: I have no knowledge base to mount a circumference calculation yet.

I need a calculation for replace the line:

CGContextSetLineDash(context, strokePhase, [strokeDash, strokeGap], 2)

to replace with a decimal number able to put 12/6/15 dashed around the circle, no matter the perimeter of circle.

Does anyone have a solution to my problem?

Where do I start?


Solution

  • iPhone 5 Issue

    As you can see from the line (from your code snippet):

    let dashedLargeRect = CGRect(x: 14.5, y: 17.5, width: 291, height: 291)
    

    the drawing space is defined of width 291 points and height 291 points.

    Hardcoding these numbers is a bad idea because, as you've noticed, it means that the code would work well only on certain devices and not in others.

    To fix this issue you can just grab these resolutions dynamically by declaring the following functions:

    func windowHeight() -> CGFloat {
          return UIScreen.mainScreen().applicationFrame.size.height
    }
    
    func windowWidth() -> CGFloat {
        return UIScreen.mainScreen().applicationFrame.size.width
    }
    

    then you can create dashedLargeRect for example:

    let dashedLargeRect = CGRect(x: 14.5, y: 17.5, width: windowWidth()-20, height: windowHeight()-20)
    

    This way you make your code device-agnostic that is always good practice. (please take note that I haven't touched the CGRect "origin", a.k.a. the x,y parameters, consider that your homework :) ).

    Second Issue

    If I understand correctly, you want to know how to draw that dashed arc.

    The secret lays on the line

    dashedLargePath.addArcWithCenter(CGPoint(x: dashedLargeRect.midX, y: dashedLargeRect.midY), radius: dashedLargeRect.width / 2, startAngle: -strokeStartAngle * CGFloat(M_PI)/180, endAngle: -strokeEndAngle * CGFloat(M_PI)/180, clockwise: true)
    

    You can see the addArcWithCenter documentation here, let me simplify it for you:

    let arcCenter = CGPoint(x: dashedLargeRect.midX, y: dashedLargeRect.midY)
    let radius = dashedLargeRect.width / 2
    let startAngle = -strokeStartAngle * CGFloat(M_PI)/180
    let endAngle = -strokeEndAngle * CGFloat(M_PI)/180
    
    dashedLargePath.addArcWithCenter(arcCenter, 
                                     radius: radius, 
                                     startAngle: startAngle, 
                                     endAngle: endAngle, 
                                     clockwise: true)
    

    now it should be much clearer what this code does, in case that you would like to draw another line over this one (for example to display the car speed, wind speed, air pressure, etc) all you have to do is call a similar function with a smaller/bigger radius and, probably, a different line style (a.k.a. change the CGContextSetLineDash, dashedLargePath.lineWidth, and UIColor.blackColor().setStroke() lines).