如何在UIView中绘制Bezier曲线 [英] How to Draw a Bezier Curve in UIView
问题描述
我需要在 UIView
中制作曲线,如下图所示。我必须使用 UIBezierPath
。请帮我解决这个问题。
我也想知道如何从水平轴上翻转曲线,这样我的弧顶部和底部都是底部。
要在特定的 CGSize
中绘制实心填充弧,您可以像这样定义 UIBezierPath
:
- (UIBezierPath * _Nullable)pathOfArcWithinSize:(CGSize)size {
if(size.width == 0 || size.height< = 0)返回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];
返回路径;
}
这只是用一点三角法来计算给定弧的角度和半径视图的高度和宽度。
一旦你有了这个,你就可以使用那个路径构造一个 CAShapeLayer
然后将其添加为 UIView
的子图层,或者您可以实现自己的 drawRect
方法,该方法调用在该路径上填写
。 (或者,鉴于您已使用
或者,如果您更愿意使用 drawRect
接近而不是使用 CAShapeLayer
:
// CurvedView.m
#importCurvedView.h
@implementation CurvedView
- (instancetype)initWithFrame :( CGRect)frame {
self = [super initWithFrame:frame];
if(self){
[self configureView];
}
返回自我;
}
- (instancetype _Nullable)initWithCoder:(NSCoder *)编码器{
self = [super initWithCoder:coder];
if(self){
[self configureView];
}
返回自我;
}
- (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];
[路径填充];
}
- (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];
返回路径;
}
@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];
返回路径;
}
基本上,这是相同的 theta
和 radius
,但从左下角开始,将中心
设置为 size.width / 2.0,radius
,以及来自 M_PI_2 * 3.0
± theta
的弧:
I need to make a curve in a UIView
as displayed in the image below. I have to use UIBezierPath
. Kindly help me out with this.
I also want to know how to flip the curve from the horizontal axis, so that I have the arc at the top and the base at the bottom.
To draw a solid filled in arc within a particular CGSize
, you can define a UIBezierPath
like so:
- (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;
}
That's just using a little trigonometry to calculate the angle and radius for the arc given the height and width of the view.
Once you have that, you can either construct a CAShapeLayer
using that path and then add that as a sublayer of a UIView
or you can implement your own drawRect
method that calls fill
on that path. (Or, given that you've tagged this with core-graphics, you could also do a custom drawRect
with CoreGraphics calls, but I'm not sure why you'd do that.)
For example, you could define a CurvedView
class that uses CAShapeLayer
:
// CurvedView.h
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface CurvedView : UIView
@property (nonatomic, strong) IBInspectable UIColor *fillColor;
@end
And
// 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
That yields:
Or, if you'd rather use the drawRect
approach rather than using 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
If you want the arc to occupy the bottom of the view, the path would look like:
- (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;
}
Essentially, that's the same theta
and radius
, but start in lower left corner, set the center
to be size.width / 2.0, radius
, and arc from M_PI_2 * 3.0
± theta
:
这篇关于如何在UIView中绘制Bezier曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!