如何在UIView中绘制Bezier曲线

时间:2016-06-14 07:08:08

标签: ios objective-c core-graphics uibezierpath

我需要在UIView中创建一条曲线,如下图所示。我必须使用UIBezierPath。请帮我解决这个问题。

我也想知道如何从水平轴上翻转曲线,这样我的弧顶部和底部的底部。

Example of bezier path

1 个答案:

答案 0 :(得分:8)

要在特定CGSize内绘制实心圆弧,您可以像这样定义UIBezierPath

- (UIBezierPath * _Nullable)pathOfArcWithinSize:(CGSize)size {
    if (size.width == 0 || size.height <= 0) return nil;

    CGFloat theta = M_PI - atan2(size.width / 2.0, size.height) * 2.0;
    CGFloat radius = self.bounds.size.height / (1.0 - cos(theta));

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(0, 0)];
    [path addArcWithCenter:CGPointMake(size.width / 2.0, -radius + size.height) radius:radius startAngle:M_PI_2 + theta endAngle:M_PI_2 - theta clockwise:false];
    [path closePath];

    return path;
}

在给定视图的高度和宽度的情况下,这只是使用一个小三角法来计算弧的角度和半径。

完成后,您可以使用该路径构建CAShapeLayer,然后将其添加为UIView的子图层,也可以实现自己的drawRect方法来调用{ {1}}在那条路上。 (或者,鉴于您已使用标记了此内容,您还可以使用CoreGraphics调用执行自定义fill,但我不确定您为什么这样做。)

例如,您可以定义使用drawRect的<{1}}类:

CurvedView

CAShapeLayer

产量:

enter image description here

或者,如果您更愿意使用// CurvedView.h #import <UIKit/UIKit.h> IB_DESIGNABLE @interface CurvedView : UIView @property (nonatomic, strong) IBInspectable UIColor *fillColor; @end 方法而非使用// CurvedView.m #import "CurvedView.h" @interface CurvedView () @property (nonatomic, weak) CAShapeLayer *curvedLayer; @end @implementation CurvedView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self configureView]; } return self; } - (instancetype _Nullable)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self configureView]; } return self; } - (void)configureView { self.fillColor = [UIColor whiteColor]; CAShapeLayer *layer = [CAShapeLayer layer]; layer.fillColor = self.fillColor.CGColor; layer.strokeColor = [UIColor clearColor].CGColor; layer.lineWidth = 0; [self.layer addSublayer:layer]; self.curvedLayer = layer; } - (void)setFillColor:(UIColor *)fillColor { _fillColor = fillColor; self.curvedLayer.fillColor = fillColor.CGColor; } - (void)layoutSubviews { [super layoutSubviews]; self.curvedLayer.path = [self pathOfArcWithinSize:self.bounds.size].CGPath; } - (UIBezierPath * _Nullable)pathOfArcWithinSize:(CGSize)size { if (size.width == 0 || size.height <= 0) return nil; CGFloat theta = M_PI - atan2(size.width / 2.0, size.height) * 2.0; CGFloat radius = self.bounds.size.height / (1.0 - cos(theta)); UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0, 0)]; [path addArcWithCenter:CGPointMake(size.width / 2.0, -radius + size.height) radius:radius startAngle:M_PI_2 + theta endAngle:M_PI_2 - theta clockwise:false]; [path closePath]; return path; } @end

drawRect

如果希望弧占据视图的底部,则路径将如下所示:

CAShapeLayer

基本上,这是// CurvedView.m #import "CurvedView.h" @implementation CurvedView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self configureView]; } return self; } - (instancetype _Nullable)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self configureView]; } return self; } - (void)configureView { self.fillColor = [UIColor whiteColor]; } - (void)setFillColor:(UIColor *)fillColor { _fillColor = fillColor; [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { UIBezierPath *path = [self pathOfArcWithinSize:self.bounds.size]; [self.fillColor setFill]; [path fill]; } - (UIBezierPath * _Nullable)pathOfArcWithinSize:(CGSize)size { if (size.width == 0 || size.height <= 0) return nil; CGFloat theta = M_PI - atan2(size.width / 2.0, size.height) * 2.0; CGFloat radius = self.bounds.size.height / (1.0 - cos(theta)); UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0, 0)]; [path addArcWithCenter:CGPointMake(size.width / 2.0, -radius + size.height) radius:radius startAngle:M_PI_2 + theta endAngle:M_PI_2 - theta clockwise:false]; [path closePath]; return path; } @end - (UIBezierPath * _Nullable)pathOfArcWithinSize:(CGSize)size { if (size.width == 0 || size.height <= 0) return nil; CGFloat theta = M_PI - atan2(size.width / 2.0, size.height) * 2.0; CGFloat radius = self.bounds.size.height / (1.0 - cos(theta)); UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0, size.height)]; [path addArcWithCenter:CGPointMake(size.width / 2.0, radius) radius:radius startAngle:M_PI_2 * 3.0 + theta endAngle:M_PI_2 * 3.0 - theta clockwise:false]; [path closePath]; return path; } 相同,但从左下角开始,将theta设为radius,并从center设置弧线±size.width / 2.0, radius

enter image description here