7

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.

rid
  • 61,078
  • 31
  • 152
  • 193
dcbenji
  • 4,598
  • 5
  • 21
  • 23
  • I would make the drawing code dependent on the size you want to draw. Scaling could lead to artifacts. – dasdom Aug 24 '14 at 05:58
  • @dasdom Add added an example of the technique I am using to draw the shape. Could you point me in the right direction as to how I could go about making the drawing dependent on the size? – dcbenji Aug 24 '14 at 06:04
  • 1
    Put the drawing code into a method with a frame parameter. Use the origin of the frame to define relative coordinates for the points which are located at the upper left and use the size and the origin to define the coordinates at the lower right. Is the drawing code with in a `drawRect:` method? – dasdom Aug 24 '14 at 06:10
  • See also http://stackoverflow.com/questions/21311880/drawing-uibezierpath-on-code-generated-uiview – Suragch Dec 08 '16 at 00:52

3 Answers3

10

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()
Jans
  • 11,064
  • 3
  • 37
  • 45
  • This works fantastic for my purpose. However it results in an annoying xcode error stating that the method is unused. Have you experienced this and is there a solution? – lifewithelliott Feb 03 '17 at 21:54
  • @lifewithelliott Those functions (e.g. offset) are actually returning values which are being ignored. You can add _ = before each of them and the warnings will be silenced (e.g. _ = offset(to: CGSize(width: vector.dx, height: vector.dy))). – rainypixels Feb 22 '17 at 19:56
  • Is it available for obj c too :(( I desperately need it. @xhamr – Reza.Ab Feb 08 '18 at 21:18
6

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.

dcbenji
  • 4,598
  • 5
  • 21
  • 23
0
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)
}
Jeffrey Berthiaume
  • 4,054
  • 3
  • 35
  • 45