iOS:CALayer,复杂的效果

时间:2013-05-05 20:47:38

标签: ios objective-c calayer

我正在尝试创建一个这样的图层:

http://data1.root-space.eu/sl/sl0j4cdz.png

但是我无法创造这种效果......有人可以帮助我吗?我找不到具有类似结果的教程。

1 个答案:

答案 0 :(得分:1)

尽管以编程方式执行此操作可能很复杂,但最简单的解决方案是使用您选择的图形工具制作表示边框的图像,将其添加到项目中,然后使用capInsets(例如{{ 3}})在调整图像大小之前,从而保留图像的边缘。


如果您想使用resizableImageWithCapInsets,可能的实现可能类似于:

3d effect on border

将Quartz.framework添加到项目中,然后定义UIView子类,如:

#import <UIKit/UIKit.h>

@interface BoxWithGradientView : UIView

@property (nonatomic) CGFloat radius;
@property (nonatomic) CGFloat lineWidth;
@property (nonatomic) CGPoint offset;

@end

实施方式如下:

#import "BoxWithGradientView.h"
#import <QuartzCore/QuartzCore.h>

@implementation BoxWithGradientView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _radius = 20.0;
        _lineWidth = 10.0;
        _offset = CGPointMake(0.0, -2.0);
    }
    return self;
}

- (void)drawLineInContext:(CGContextRef)context
                     from:(CGPoint)startPoint
                       to:(CGPoint)endPoint
            usingGradient:(CGGradientRef)gradient
{
    CGContextSaveGState(context);

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

    CGContextAddLineToPoint(context, endPoint.x, endPoint.y);

    CGContextSetLineWidth(context, self.lineWidth);

    CGFloat angle = atan2f(endPoint.y - startPoint.y, endPoint.x - startPoint.x);
    CGPoint start = CGPointMake(startPoint.x - sinf(angle) * self.lineWidth / 2.0 + self.offset.x,
                                startPoint.y - cosf(angle) * self.lineWidth / 2.0 + self.offset.y);
    CGPoint end   = CGPointMake(startPoint.x + sinf(angle) * self.lineWidth / 2.0 + self.offset.x,
                                startPoint.y + cosf(angle) * self.lineWidth / 2.0 + self.offset.y);

    CGContextReplacePathWithStrokedPath(context);
    CGContextClip(context);
    CGContextDrawLinearGradient(context, gradient, start, end, kCGGradientDrawsAfterEndLocation | kCGGradientDrawsBeforeStartLocation);

    CGContextRestoreGState(context);
}

- (void)drawArcInContext:(CGContextRef)context
                  center:(CGPoint)center
                  radius:(CGFloat)radius
              startAngle:(CGFloat)startAngle
                endAngle:(CGFloat)endAngle
               clockwise:(BOOL)clockwise
           usingGradient:(CGGradientRef)gradient
{
    CGContextSaveGState(context);

    CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, clockwise);
    // CGContextMoveToPoint(context, startPoint.x, startPoint.y);

    CGContextSetLineWidth(context, self.lineWidth);

    CGPoint gradientCenter = center;
    gradientCenter.x += self.offset.x;
    gradientCenter.y += self.offset.y;

    CGContextReplacePathWithStrokedPath(context);
    CGContextClip(context);
    CGContextDrawRadialGradient(context,
                                gradient,
                                gradientCenter,
                                radius - self.lineWidth / 2.0,
                                gradientCenter,
                                radius + self.lineWidth / 2.0,
                                kCGGradientDrawsAfterEndLocation | kCGGradientDrawsBeforeStartLocation);

    CGContextRestoreGState(context);
}

- (void)drawRect:(CGRect)rect
{
    // Create a gradient from black to blue to black
    CGFloat colors [] = {
        0.0, 0.0, 2.0, 1.0,
        0.7, 0.7, 1.0, 1.0,
        0.0, 0.0, 2.0, 1.0,
    };

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 3);
    CGColorSpaceRelease(colorSpace);

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetAllowsAntialiasing(context, YES);

    // top

    [self drawLineInContext:context
                       from:CGPointMake(self.radius + self.lineWidth / 2.0,
                                        self.lineWidth / 2.0)
                         to:CGPointMake(rect.size.width - self.radius - self.lineWidth / 2.0,
                                        self.lineWidth / 2.0)
              usingGradient:gradient];

    // top right corner

    [self drawArcInContext:context
                    center:CGPointMake(rect.size.width - self.radius - self.lineWidth / 2.0,
                                       self.radius + self.lineWidth / 2.0)
                    radius:self.radius
                startAngle:M_PI_2 * 3.0
                  endAngle:M_PI * 2.0
                 clockwise:NO
             usingGradient:gradient];

    // right

    [self drawLineInContext:context
                       from:CGPointMake(rect.size.width - self.lineWidth / 2.0,
                                        self.radius + self.lineWidth / 2.0)
                         to:CGPointMake(rect.size.width - self.lineWidth / 2.0,
                                        rect.size.height - self.radius - self.lineWidth / 2.0)
              usingGradient:gradient];

    // lower right corner

    [self drawArcInContext:context
                    center:CGPointMake(rect.size.width - self.radius - self.lineWidth / 2.0,
                                       rect.size.height - self.radius - self.lineWidth / 2.0)
                    radius:self.radius
                startAngle:0.0
                  endAngle:M_PI_2
                 clockwise:NO
             usingGradient:gradient];

    // bottom

    [self drawLineInContext:context
                       from:CGPointMake(self.radius + self.lineWidth / 2.0,
                                        rect.size.height - self.lineWidth / 2.0)
                         to:CGPointMake(rect.size.width - self.radius - self.lineWidth / 2.0,
                                        rect.size.height - self.lineWidth / 2.0)
              usingGradient:gradient];

    // bottom left corner

    [self drawArcInContext:context
                    center:CGPointMake(self.radius + self.lineWidth / 2.0,
                                       rect.size.height - self.radius - self.lineWidth / 2.0)
                    radius:self.radius
                startAngle:M_PI_2
                  endAngle:M_PI
                 clockwise:NO
             usingGradient:gradient];

    // left

    [self drawLineInContext:context
                       from:CGPointMake(self.lineWidth / 2.0,
                                        self.radius + self.lineWidth / 2.0)
                         to:CGPointMake(self.lineWidth / 2.0,
                                        rect.size.height - self.radius - self.lineWidth / 2.0)
              usingGradient:gradient];

    // top left corner

    [self drawArcInContext:context
                    center:CGPointMake(self.radius + self.lineWidth / 2.0,
                                       self.radius + self.lineWidth / 2.0)
                    radius:self.radius
                startAngle:M_PI
                  endAngle:M_PI_2 * 3.0
                 clockwise:NO
             usingGradient:gradient];
}

#pragma mark - setters will redraw

- (void)setRadius:(CGFloat)radius
{
    _radius = radius;

    [self setNeedsDisplay];
}

- (void)setLineWidth:(CGFloat)lineWidth
{
    _lineWidth = lineWidth;

    [self setNeedsDisplay];
}

- (void)setOffset:(CGPoint)offset
{
    _offset = offset;

    [self setNeedsDisplay];
}

@end

然后,您可以在视图控制器中使用它,如:

- (void)viewDidAppear:(BOOL)animated
{
    CGFloat margin = 3.0;
    CGRect frame = CGRectMake(margin,
                              margin,
                              self.view.frame.size.width - margin * 2,
                              self.view.frame.size.height - margin * 2);

    BoxWithGradientView *boxWithGradientView = [[BoxWithGradientView alloc] initWithFrame:frame];
    boxWithGradientView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:boxWithGradientView];
}

显然,您可以使用渐变(尽管保持对称,否则您将不得不调整代码),但它是一种可能的CoreGraphics实现。我怀疑有更好的方法来实现更复杂的效果,但它会让你非常接近。