如何使用Quartz Core绘制星星?

我试图改编苹果公司提供的一个例子,以编程方式绘制星星,代码如下:

CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, aSize); for (NSUInteger i=0; i<stars; i++) { CGContextSetFillColorWithColor(context, aColor); CGContextSetStrokeColorWithColor(context, aColor); float w = item.size.width; double r = w / 2; double theta = 2 * M_PI * (2.0 / 5.0); // 144 degrees CGContextMoveToPoint(context, 0, r); for (NSUInteger k=1; k<5; k++) { float x = r * sin(k * theta); float y = r * cos(k * theta); CGContextAddLineToPoint(context, x, y); } CGContextClosePath(context); CGContextFillPath(context); } 

上面的代码绘制了一个完美的明星,但是是1.颠倒显示2.是黑色的,没有边界。 我想要做的是在同一条线上画出许多恒星,并用给定的风格。 我明白,我实际上在同一个位置上绘制了相同的path5次,并且我以某种方式垂直翻转上下文,但经过多次testing,我放弃了! (我缺乏必要的math和几何技能:P)…你能帮我吗?

更新:

好的,感谢CocoaFu ,这是我重构和工作的绘图工具:

 - (void)drawStars:(NSUInteger)count inContext:(CGContextRef)context; { // constants const float w = self.itemSize.width; const float r = w/2; const double theta = 2 * M_PI * (2.0 / 5.0); const float flip = -1.0f; // flip vertically (default star representation) // drawing center for the star float xCenter = r; for (NSUInteger i=0; i<count; i++) { // get star style based on the index CGContextSetFillColorWithColor(context, [self fillColorForItemAtIndex:i]); CGContextSetStrokeColorWithColor(context, [self strokeColorForItemAtIndex:i]); // update position CGContextMoveToPoint(context, xCenter, r * flip + r); // draw the necessary star lines for (NSUInteger k=1; k<5; k++) { float x = r * sin(k * theta); float y = r * cos(k * theta); CGContextAddLineToPoint(context, x + xCenter, y * flip + r); } // update horizontal center for the next star xCenter += w + self.itemMargin; // draw current star CGContextClosePath(context); CGContextFillPath(context); CGContextStrokePath(context); } } 

这里是代码,将水平线画3星,这是不漂亮,但它可能有所帮助:

 -(void)drawRect:(CGRect)rect { int aSize = 100.0; const CGFloat color[4] = { 0.0, 0.0, 1.0, 1.0 }; // Blue CGColorRef aColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), color); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, aSize); CGFloat xCenter = 100.0; CGFloat yCenter = 100.0; float w = 100.0; double r = w / 2.0; float flip = -1.0; for (NSUInteger i=0; i<3; i++) { CGContextSetFillColorWithColor(context, aColor); CGContextSetStrokeColorWithColor(context, aColor); double theta = 2.0 * M_PI * (2.0 / 5.0); // 144 degrees CGContextMoveToPoint(context, xCenter, r*flip+yCenter); for (NSUInteger k=1; k<5; k++) { float x = r * sin(k * theta); float y = r * cos(k * theta); CGContextAddLineToPoint(context, x+xCenter, y*flip+yCenter); } xCenter += 150.0; } CGContextClosePath(context); CGContextFillPath(context); } 

在这里输入图像说明

下面是一个实现buddhabrot暗示的algorithm:

 - (void)drawStarInContext:(CGContextRef)context withNumberOfPoints:(NSInteger)points center:(CGPoint)center innerRadius:(CGFloat)innerRadius outerRadius:(CGFloat)outerRadius fillColor:(UIColor *)fill strokeColor:(UIColor *)stroke strokeWidth:(CGFloat)strokeWidth { CGFloat arcPerPoint = 2.0f * M_PI / points; CGFloat theta = M_PI / 2.0f; // Move to starting point (tip at 90 degrees on outside of star) CGPoint pt = CGPointMake(center.x - (outerRadius * cosf(theta)), center.y - (outerRadius * sinf(theta))); CGContextMoveToPoint(context, pt.x, pt.y); for (int i = 0; i < points; i = i + 1) { // Calculate next inner point (moving clockwise), accounting for crossing of 0 degrees theta = theta - (arcPerPoint / 2.0f); if (theta < 0.0f) { theta = theta + (2 * M_PI); } pt = CGPointMake(center.x - (innerRadius * cosf(theta)), center.y - (innerRadius * sinf(theta))); CGContextAddLineToPoint(context, pt.x, pt.y); // Calculate next outer point (moving clockwise), accounting for crossing of 0 degrees theta = theta - (arcPerPoint / 2.0f); if (theta < 0.0f) { theta = theta + (2 * M_PI); } pt = CGPointMake(center.x - (outerRadius * cosf(theta)), center.y - (outerRadius * sinf(theta))); CGContextAddLineToPoint(context, pt.x, pt.y); } CGContextClosePath(context); CGContextSetLineWidth(context, strokeWidth); [fill setFill]; [stroke setStroke]; CGContextDrawPath(context, kCGPathFillStroke); } 

为我工作对于大多数基本的星星。 testing从2点(做一个好钻石!)达到9星。

如果你想要一个有点下降的星星,将减法改为加法。

要绘制倍数,创build一个循环并多次调用此方法,每次传递一个新的中心。 这应该排队他们很好!

我更喜欢使用CAShaperLayer来实现drawRect ,因为它可以被animation化。 这里有一个函数可以创build一个5点星形的path:

 func createStarPath(size: CGSize) -> CGPath { let numberOfPoints: CGFloat = 5 let starRatio: CGFloat = 0.5 let steps: CGFloat = numberOfPoints * 2 let outerRadius: CGFloat = min(size.height, size.width) / 2 let innerRadius: CGFloat = outerRadius * starRatio let stepAngle = CGFloat(2) * CGFloat(M_PI) / CGFloat(steps) let center = CGPoint(x: size.width / 2, y: size.height / 2) let path = CGPathCreateMutable() for i in 0..<Int(steps) { let radius = i % 2 == 0 ? outerRadius : innerRadius let angle = CGFloat(i) * stepAngle - CGFloat(M_PI_2) let x = radius * cos(angle) + center.x let y = radius * sin(angle) + center.y if i == 0 { CGPathMoveToPoint(path, nil, x, y) } else { CGPathAddLineToPoint(path, nil, x, y) } } CGPathCloseSubpath(path) return path } 

然后它可以像CAShapeLayer一样使用:

 let layer = CAShapeLayer() layer.path = createStarPath(CGSize(width: 100, height: 100)) layer.lineWidth = 1 layer.strokeColor = UIColor.blackColor().CGColor layer.fillColor = UIColor.yellowColor().CGColor layer.fillRule = kCAFillRuleNonZero