简体   繁体   中英

How do I make a UIImage being drawn with drawInRect using a UIBezierPath?

I have a custom UIView I'm doing drawing in, and in the drawRect function I'm creating a circle shape (with a hollow center, so picture a donut) as a UIBezierPath .

I then want to use this UIBezierPath /circle shape as the mask for when I draw my UIImage with drawInRect . So in the end I'll have a donut shape with an image background.

I create the circle/ UIBezierPath as follows:

let context = UIGraphicsGetCurrentContext()
let progress = CGFloat(1.0)
let diameter = CGFloat(32.0)

let gapExpression: CGFloat = diameter * CGFloat(M_PI)
let dashExpression: CGFloat = progress * diameter * CGFloat(M_PI)

CGContextSaveGState(context)
CGContextTranslateCTM(context, 19, 19)
CGContextRotateCTM(context, -270 * CGFloat(M_PI) / 180)

var circlePath = UIBezierPath()
circlePath.moveToPoint(CGPointMake(-16, 0))
circlePath.addCurveToPoint(CGPointMake(0, -16), controlPoint1: CGPointMake(-16, -8.84), controlPoint2: CGPointMake(-8.84, -16))
circlePath.addCurveToPoint(CGPointMake(16, 0), controlPoint1: CGPointMake(8.84, -16), controlPoint2: CGPointMake(16, -8.84))
circlePath.addCurveToPoint(CGPointMake(0, 16), controlPoint1: CGPointMake(16, 8.84), controlPoint2: CGPointMake(8.84, 16))
circlePath.addCurveToPoint(CGPointMake(-16, 0), controlPoint1: CGPointMake(-8.84, 16), controlPoint2: CGPointMake(-16, 8.84))
circlePath.closePath()
circlePath.lineCapStyle = kCGLineCapRound;

UIColor.grayColor().setStroke()
circlePath.lineWidth = 5
CGContextSaveGState(context)
CGContextSetLineDash(context, 0, [dashExpression, gapExpression], 2)
circlePath.stroke()
CGContextRestoreGState(context)

Which if I just have that in my drawRect it outputs a circle/donut shape.

However I also have a UIImage :

let image = UIImage(named: "test-shape")

That I draw using drawInRect , but I want the image to be masked by the UIBezierPath above.

How would I accomplish this?

Save the context, add a clip, set the scale, and draw the image.

This should be close:

circlePath.lineCapStyle = kCGLineCapRound;      // existing

// add these lines
CGContextSaveGState(context)
circlePath.addClip()
CGContextScaleCTM(context, 1, -1)
CGContextDrawTiledImage(context, CGRectMake(0, 0, test-shape.size.width, test-shape.size.height), test-shape.CGImage)
CGContextRestoreGState(context)

UIColor.grayColor().setStroke()                 //existing

Edit to add alternative: This draws a donut and fills it with the image. But the line dash is not probably going to have the effect you need. Perhaps this can help in some way.

let context = UIGraphicsGetCurrentContext()

let testshape = UIImage(named: "testshape.png")!

var circlePath = UIBezierPath()
circlePath.moveToPoint(CGPointMake(9.5, 2.5))
circlePath.addCurveToPoint(CGPointMake(6.1, 3.38), controlPoint1: CGPointMake(8.27, 2.5), controlPoint2: CGPointMake(7.11, 2.82))
circlePath.addCurveToPoint(CGPointMake(2.5, 9.5), controlPoint1: CGPointMake(3.95, 4.58), controlPoint2: CGPointMake(2.5, 6.87))
circlePath.addCurveToPoint(CGPointMake(9.5, 16.5), controlPoint1: CGPointMake(2.5, 13.37), controlPoint2: CGPointMake(5.63, 16.5))
circlePath.addCurveToPoint(CGPointMake(16.5, 9.5), controlPoint1: CGPointMake(13.37, 16.5), controlPoint2: CGPointMake(16.5, 13.37))
circlePath.addCurveToPoint(CGPointMake(9.5, 2.5), controlPoint1: CGPointMake(16.5, 5.63), controlPoint2: CGPointMake(13.37, 2.5))
circlePath.closePath()
circlePath.moveToPoint(CGPointMake(19, 9.5))
circlePath.addCurveToPoint(CGPointMake(9.5, 19), controlPoint1: CGPointMake(19, 14.75), controlPoint2: CGPointMake(14.75, 19))
circlePath.addCurveToPoint(CGPointMake(0, 9.5), controlPoint1: CGPointMake(4.25, 19), controlPoint2: CGPointMake(-0, 14.75))
circlePath.addCurveToPoint(CGPointMake(3.88, 1.84), controlPoint1: CGPointMake(0, 6.36), controlPoint2: CGPointMake(1.53, 3.57))
circlePath.addCurveToPoint(CGPointMake(9.5, 0), controlPoint1: CGPointMake(5.45, 0.68), controlPoint2: CGPointMake(7.4, 0))
circlePath.addCurveToPoint(CGPointMake(19, 9.5), controlPoint1: CGPointMake(14.75, 0), controlPoint2: CGPointMake(19, 4.25))
circlePath.closePath()
circlePath.lineCapStyle = kCGLineCapRound;

CGContextSaveGState(context)
circlePath.addClip()
CGContextScaleCTM(context, 1, -1)
CGContextDrawTiledImage(context, CGRectMake(0, 0, testshape.size.width, testshape.size.height), testshape.CGImage)
CGContextRestoreGState(context)

甜甜圈

If you just want a half circle, here is a quick example of how to draw that. Just use that as the mask. Rotate as needed.

let color = UIColor(red: 0.742, green: 0.000, blue: 1.000, alpha: 1.000)

var bezierPath = UIBezierPath()
bezierPath.moveToPoint(CGPointMake(56, 45))
bezierPath.addCurveToPoint(CGPointMake(31, 70), controlPoint1: CGPointMake(56, 58.81), controlPoint2: CGPointMake(44.81, 70))
bezierPath.addCurveToPoint(CGPointMake(26, 65), controlPoint1: CGPointMake(28.24, 70), controlPoint2: CGPointMake(26, 67.76))
bezierPath.addCurveToPoint(CGPointMake(31, 60), controlPoint1: CGPointMake(26, 62.24), controlPoint2: CGPointMake(28.24, 60))
bezierPath.addCurveToPoint(CGPointMake(46, 45), controlPoint1: CGPointMake(39.28, 60), controlPoint2: CGPointMake(46, 53.28))
bezierPath.addCurveToPoint(CGPointMake(31, 30), controlPoint1: CGPointMake(46, 36.72), controlPoint2: CGPointMake(39.28, 30))
bezierPath.addCurveToPoint(CGPointMake(26, 25), controlPoint1: CGPointMake(28.24, 30), controlPoint2: CGPointMake(26, 27.76))
bezierPath.addCurveToPoint(CGPointMake(29.45, 20.24), controlPoint1: CGPointMake(26, 22.78), controlPoint2: CGPointMake(27.45, 20.9))
bezierPath.addCurveToPoint(CGPointMake(31, 20), controlPoint1: CGPointMake(29.94, 20.09), controlPoint2: CGPointMake(30.46, 20))
bezierPath.addCurveToPoint(CGPointMake(56, 45), controlPoint1: CGPointMake(44.81, 20), controlPoint2: CGPointMake(56, 31.19))
bezierPath.closePath()
color.setFill()
bezierPath.fill()

圆头半圆

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM