iphone - 使用核心图形绘制浮雕弧

标签 iphone ios core-graphics

我正在尝试实现一个自定义 slider ,如下图所示。

enter image description here

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

enter image description here

请帮我画出这样效果的圆弧。我的代码如下,我正在做的是使用线宽为 kLineWidth 的 CGContextAddArc 绘制圆弧。

- (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 中创建这种效果很容易。

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

  1. 剪辑到形状(使用例如 CGContextClipCGContextClipToMask)。
  2. 形状以外的所有东西制作路径或 mask 。
  3. 设置阴影参数(使用 CGContextSetShadowWithColor)。
  4. 填充步骤 2 中的路径或蒙版。这会在形状内部转换阴影,并且只绘制阴影,因为您在步骤 1 中剪裁到形状。

如果你做对了所有这些,你会得到这样一个不错的结果:

screen shot of arc with inner shadow

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

- (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];

接下来,我要求 Core Graphics 创建一条新路径,即 arc 路径的轮廓。请注意我如何要求它的笔画宽度为 kArcThickness 和圆线帽:

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

我还需要该路径的逆:包含shape 中的点的所有点的路径。 CGContextCreateCopyByStrokingPathCGPathAddRect 绘制方向相反(尽管我认为没有记录)就这样发生了。因此,如果我复制 shape 并在其周围画一个巨大的矩形,非零缠绕规则意味着新路径将是 shape 的倒数:

    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); {

第 1 步:剪裁形状:

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

第 2 步:嗯,我在创建 shapeInverse 时已经执行了这一步。

第 3 步:设置阴影参数:

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

第 4 步:我填充第 2 步中的反向形状:

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

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

    } CGContextRestoreGState(gc);

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

    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);
}

更复杂的形状可以看my answer heremy answer here .

为了方便复制,这里把所有的代码放在一起:

- (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);
}

关于iphone - 使用核心图形绘制浮雕弧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10417982/

相关文章:

iphone - 设备上的神秘 tableView 没有保留在代码中

iphone - SymbolicateCrash 没有创建正确的反符号文件

javascript - iOS 上的 UIWebView 是否有向 DOM 添加接口(interface)的方法?

ios - 在不同设备上使用同一帐户数据不同步

iphone - 设置需要显示矩形 : paints a white rectangle only

ios - 核心图形旋转矩形

iphone - 这里如何获取和修改一个像素值?

iphone - rss 阅读 iphone/ipad 应用程序

iphone - IOS中如何将数据从一个 View 传递到另一个 View Controller ?

ios - 如何在 viewdidload() 中使用 CLLocation 的位置(纬度、经度)