使用核心图形绘制浮雕弧 [英] draw embossed arc using core graphics

查看:78
本文介绍了使用核心图形绘制浮雕弧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现自定义滑块,如下图所示。

I am trying to implement a custom slider as shown in figure below.

到目前为止我所做的事情看起来像这样

what I have done so far looks something like this

请帮帮我用于绘制具有这种效果的弧。我的代码如下所示,我正在做的是使用线宽为kLineWidth的CGContextAddArc绘制弧。

please help me out for drawing the arc with such effect. my code is as below, what I am doing is drawing the arc using CGContextAddArc with line width kLineWidth.

- (void)drawThumbAtPoint:(CGPoint)sliderButtonCenterPoint inContext: (CGContextRef)context {
UIGraphicsPushContext(context);
CGContextBeginPath(context);

CGContextMoveToPoint(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y);

CGImageRef imageRef = [UIImage imageNamed:@"circle25.png"].CGImage;
CGRect rect = CGRectMake(sliderButtonCenterPoint.x - kThumbRadius, sliderButtonCenterPoint.y - kThumbRadius, kThumbRadius*2, kThumbRadius*2);
CGContextDrawImage(context, rect, imageRef);

//CGContextAddArc(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y, kThumbRadius, 0.0, 2*M_PI, NO);

CGContextFillPath(context);
UIGraphicsPopContext();
}

- (CGPoint)drawArcTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius inContext:(CGContextRef)context {
UIGraphicsPushContext(context);
CGContextBeginPath(context);

float angleFromTrack = translateValueFromSourceIntervalToDestinationInterval(track, self.minimumValue, self.maximumValue, 0, M_PI/3);// 2*M_PI

CGFloat startAngle = (4*M_PI)/3;
CGFloat endAngle = startAngle + angleFromTrack;

CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, NO);

CGPoint arcEndPoint = CGContextGetPathCurrentPoint(context);

CGContextStrokePath(context);   

UIGraphicsPopContext();

return arcEndPoint;
}

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGPoint middlePoint;
    middlePoint.x = self.bounds.origin.x + self.bounds.size.width/2;
middlePoint.y = self.bounds.origin.y + self.bounds.size.width;

CGContextSetLineWidth(context, kLineWidth);

CGFloat radius = [self sliderRadius];


[self.maximumTrackTintColor setStroke];         
[self drawArcTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];          
[self.minimumTrackTintColor setStroke];         
self.thumbCenterPoint = [self drawArcTrack:self.value atPoint:middlePoint withRadius:radius inContext:context];     

[self.thumbTintColor setFill];
[self drawThumbAtPoint:self.thumbCenterPoint inContext:context];
}


推荐答案

除非你要成为动态改变形状,你可能最好只在图像编辑器中创建图像。我知道在Photoshop,Illustrator或Fireworks中创建该效果很容易。

Unless you are going to be changing the shape dynamically, you would probably be better off just creating the image in an image editor. I know it's easy to create that effect in Photoshop, Illustrator, or Fireworks.

也就是说,使用Core Graphics绘制内部阴影需要几个步骤:

That said, drawing an inner shadow like that with Core Graphics requires several steps:


  1. 剪辑到形状(使用例如 CGContextClip CGContextClipToMask )。

  2. 制作形状的路径或掩码。

  3. 设置阴影参数(使用 CGContextSetShadowWithColor )。

  4. 填充步骤2中的路径或掩码。这会在形状内部投射阴影,并且只有阴影被绘制,因为你在步骤1中剪切了形状。

  1. Clip to the shape (using e.g. CGContextClip or CGContextClipToMask).
  2. Make a path or mask of everything but the shape.
  3. Set your shadow parameters (using CGContextSetShadowWithColor).
  4. Fill the path or mask from step 2. This casts a shadow inside the shape, and only the shadow is drawn because you clipped to the shape in step 1.

如果你正确地完成所有这些,你可以得到一个很好的结果像这样:

If you do all of that correctly, you can get a nice result like this:

这是我写的用来绘制的代码。我在自定义视图子类的 drawRect:中编写了它,但您可以轻松地使用此代码绘制到任何图形上下文中。

Here's the code I wrote to draw that. I wrote it in the drawRect: of a custom view subclass, but you can easily use this code to draw into any graphics context.

- (void)drawRect:(CGRect)rect {
    CGContextRef gc = UIGraphicsGetCurrentContext();

首先,我创建一个只是弧形的路径:

First, I create a path that's just an arc:

    static CGFloat const kArcThickness = 20.0f;
    CGRect arcBounds = CGRectInset(self.bounds, 10.0f, 10.0f);
    CGPoint arcCenter = CGPointMake(CGRectGetMidX(arcBounds), CGRectGetMidY(arcBounds));
    CGFloat arcRadius = 0.5f * (MIN(arcBounds.size.width, arcBounds.size.height) - kArcThickness);
    UIBezierPath *arc = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:arcRadius startAngle:-M_PI / 3.0 endAngle:-2.0 * M_PI / 3.0 clockwise:NO];

接下来,我要求Core Graphics制作一条新路径,该路径是<$ c $的大纲c> arc 路径。请注意我如何要求它的笔画宽度 kArcThickness 和圆线上限:

Next, I ask Core Graphics to make a new path that is the outline of the arc path. Note how I ask it for a stroke width of kArcThickness and round line caps:

    CGPathRef shape = CGPathCreateCopyByStrokingPath(arc.CGPath, NULL, kArcThickness, kCGLineCapRound, kCGLineJoinRound, 10.0f);

我还需要该路径的反转:包含的每个点的路径,除了 形状中的点数。它发生了(尽管我认为没有记录), CGContextCreateCopyByStrokingPath CGPathAddRect 以相反的方向绘制。因此,如果我复制 shape 并在其周围绘制一个巨大的矩形,则非零缠绕规则意味着新路径将与 shape

I also need the inverse of that path: a path that includes every point except the points in shape. It so happens (although I don't think it's documented) that CGContextCreateCopyByStrokingPath and CGPathAddRect draw in opposite directions. So if I copy shape and draw an enormous rectangle around it, the non-zero winding rule means that the new path will be the inverse of shape:

    CGMutablePathRef shapeInverse = CGPathCreateMutableCopy(shape);
    CGPathAddRect(shapeInverse, NULL, CGRectInfinite);

现在我可以开始绘画了。首先,我将用浅灰色填充形状:

Now I can actually start drawing. First, I'll fill in the shape with a light gray color:

    CGContextBeginPath(gc);
    CGContextAddPath(gc, shape);
    CGContextSetFillColorWithColor(gc, [UIColor colorWithWhite:.9 alpha:1].CGColor);
    CGContextFillPath(gc);

接下来我实际执行上面列出的四个步骤。我必须保存图形状态,以便在完成后撤消剪切和阴影参数。

Next I actually perform the four steps I listed above. I have to save the graphics state so I can undo the clipping and shadow parameters when I'm done.

    CGContextSaveGState(gc); {

第1步:剪辑到形状:

        CGContextBeginPath(gc);
        CGContextAddPath(gc, shape);
        CGContextClip(gc);

第2步:嗯,我在创建 shapeInverse时已经执行了此步骤/ code>。

Step 2: Well, I did this step already when I created shapeInverse.

第3步:我设置了阴影参数:

Step 3: I set the shadow parameters:

        CGContextSetShadowWithColor(gc, CGSizeZero, 7, [UIColor colorWithWhite:0 alpha:.25].CGColor);

步骤4:我填写第2步的反转形状:

Step 4: I fill the inverse shape from step 2:

        CGContextBeginPath(gc);
        CGContextAddPath(gc, shapeInverse);
        CGContextFillPath(gc);

现在我恢复图形状态,专门恢复剪切路径并取消设置阴影参数。

Now I restore the graphics state, which specifically restores the clipping path and unsets the shadow parameters.

    } CGContextRestoreGState(gc);

最后,我将使用 shape 浅灰色使边缘更清晰:

Finally, I'll stroke shape with a light gray to make the edge crisper:

    CGContextSetStrokeColorWithColor(gc, [UIColor colorWithWhite:.75 alpha:1].CGColor);
    CGContextSetLineWidth(gc, 1);
    CGContextSetLineJoin(gc, kCGLineCapRound);
    CGContextBeginPath(gc);
    CGContextAddPath(gc, shape);
    CGContextStrokePath(gc);

当我完成后我会清理:

    CGPathRelease(shape);
    CGPathRelease(shapeInverse);
}

对于更复杂的形状,你可以看一下我在这里回答我的答案在这里

For more complex shapes, you can look at my answer here and my answer here.

以下是所有代码,以便于复制:

Here's all the code together for easy copying:

- (void)drawRect:(CGRect)rect {
    CGContextRef gc = UIGraphicsGetCurrentContext();

    static CGFloat const kArcThickness = 20.0f;
    CGRect arcBounds = CGRectInset(self.bounds, 10.0f, 10.0f);
    CGPoint arcCenter = CGPointMake(CGRectGetMidX(arcBounds), CGRectGetMidY(arcBounds));
    CGFloat arcRadius = 0.5f * (MIN(arcBounds.size.width, arcBounds.size.height) - kArcThickness);
    UIBezierPath *arc = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:arcRadius startAngle:-M_PI / 3.0 endAngle:-2.0 * M_PI / 3.0 clockwise:NO];
    CGPathRef shape = CGPathCreateCopyByStrokingPath(arc.CGPath, NULL, kArcThickness, kCGLineCapRound, kCGLineJoinRound, 10.0f);
    CGMutablePathRef shapeInverse = CGPathCreateMutableCopy(shape);
    CGPathAddRect(shapeInverse, NULL, CGRectInfinite);

    CGContextBeginPath(gc);
    CGContextAddPath(gc, shape);
    CGContextSetFillColorWithColor(gc, [UIColor colorWithWhite:.9 alpha:1].CGColor);
    CGContextFillPath(gc);

    CGContextSaveGState(gc); {
        CGContextBeginPath(gc);
        CGContextAddPath(gc, shape);
        CGContextClip(gc);
        CGContextSetShadowWithColor(gc, CGSizeZero, 7, [UIColor colorWithWhite:0 alpha:.25].CGColor);
        CGContextBeginPath(gc);
        CGContextAddPath(gc, shapeInverse);
        CGContextFillPath(gc);
    } CGContextRestoreGState(gc);

    CGContextSetStrokeColorWithColor(gc, [UIColor colorWithWhite:.75 alpha:1].CGColor);
    CGContextSetLineWidth(gc, 1);
    CGContextSetLineJoin(gc, kCGLineCapRound);
    CGContextBeginPath(gc);
    CGContextAddPath(gc, shape);
    CGContextStrokePath(gc);

    CGPathRelease(shape);
    CGPathRelease(shapeInverse);
}

这篇关于使用核心图形绘制浮雕弧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆