如何在UIView中绘制贝塞尔曲线
我需要在UIView
制作曲线,如下图所示。 我必须使用UIBezierPath
。 请帮我解决这个问题。
我也想知道如何从水平轴上翻转曲线,这样我的弧顶部和底部的底部。
要在一个特定的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; }
这只是使用一个小三angular来计算视angular的高度和宽度的弧的angular度和半径。
一旦你有了,你可以使用该path构build一个CAShapeLayer
,然后将其添加为一个UIView
的子层,或者你可以实现自己的drawRect
方法来调用fill
path。 (或者,你已经用core-graphics标记了这个标记,你也可以用CoreGraphics调用自定义drawRect
,但是我不确定为什么要这样做。)
例如,您可以定义一个使用CAShapeLayer
的CurvedView
类:
// 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
如果您想让弧线占据视图的底部,则path将如下所示:
- (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
,但从左下angular开始,将center
设置为size.width / 2.0, radius
和arc从M_PI_2 * 3.0
± theta
: