dcbenji
dcbenji

Reputation: 4678

How to Scale UIBezierPath to Fit Current View (in Swift)

I've created a class that draws a coffee mug using code I imported from PaintCode and I applied this class to a view. Using @IBDesignable, I can see in my storyboard that the mug is being drawn inside the view, however the overall shape is too big. I could redraw the shape in code so that it fits the current size of the view, but isn't there a way to scale the shape after it is drawn so that as my view changes size on different devices the shape is scaled correctly?

I've looked into CGContextScaleCTM(aRef, <#sx: CGFloat#>, <#sy: CGFloat#>) but I am not sure how to convert the CGRect of my view's bounds to the right scale factor

I didn't want to post all of it, but my drawing code begins like this

bezierPath.moveToPoint(CGPointMake(64.8, 52.81))
bezierPath.addCurveToPoint(CGPointMake(58.89, 43.44), controlPoint1: CGPointMake(64.21, 48.28), controlPoint2: CGPointMake(62.11, 44.95))
bezierPath.addCurveToPoint(CGPointMake(56.82, 42.76), controlPoint1: CGPointMake(58.24, 43.13), controlPoint2: CGPointMake(57.55, 42.9))

This goes on then

bezierPath.closePath()
bezierPath.miterLimit = 4
bezierPath.usesEvenOddFillRule = true;

Then there are are two other chunks of drawing code for drawing two little lines for the coffee steam. I append these two paths to the original bezierPath, then I set a fill color and fill the whole shape.

Upvotes: 8

Views: 5564

Answers (3)

Jeffrey Berthiaume
Jeffrey Berthiaume

Reputation: 4594

func scalePath(path: UIBezierPath) -> UIBezierPath {
    
    let w1: CGFloat = path.bounds.size.width
    let h1: CGFloat = path.bounds.size.height
    
    let w2: CGFloat = self.frame.width
    let h2: CGFloat = self.frame.height
    
    var s: CGFloat = 1.0
    
    // take the smaller one and scale 1:1 to fit (to keep the aspect ratio)
    if w2 <= h2 {
        s = w2 / w1
    } else {
        s = h2 / h1
    }
    
    path.apply(CGAffineTransform(scaleX: s, y: s))
    
    return (path)
}

Upvotes: 1

Jans
Jans

Reputation: 11250

In code you can just scale your paths as you want using this UIBezierPath swift extension PaintCodeScale.

e.g

bezierPath.fit(into: rect).moveCenter(to: rect.center).fill()

Upvotes: 10

dcbenji
dcbenji

Reputation: 4678

Since I used PaintCode to generate my drawing code, I found a way to implement @dasdom's suggestion using help from the app.

In PaintCode there is a "frame" tool which you can place around your drawing. This enables constraints for your artwork so that the vectors are re-drawn relative to the frame size. The frame is a variable that is exported along with your code when you bring it into Xcode. When I added the drawing code to my class in Xcode and then added the class to my view in Storyboard, Xcode automatically scaled the frame to the view size and thus the drawing code within my class was also autmatically resized to fit my view. Now, the artwork will be automatically re-drawn to fit whatever view I add my class to. The automatic re-sizing may be occurring due to the "Automatically resize subviews" option that is enabled in Storyboard for the view that I have applied my graphics class to.

Upvotes: 6

Related Questions