开源软件名称:UIBezierPath_CAShapeLayer
开源软件地址:https://gitee.com/Lee_Jay/UIBezierPath_CAShapeLayer
开源软件介绍:
UIBezierPath和CAShapeLayer绘图UIBezierPath官方文档 The UIBezierPath class lets you define a path consisting of straight and curved line segments and render that path in your custom views. You use this class initially to specify just the geometry for your path. Paths can define simple shapes such as rectangles, ovals, and arcs or they can define complex polygons that incorporate a mixture of straight and curved line segments. After defining the shape, you can use additional methods of this class to render the path in the current drawing context.
UIBezierPath 类允许你在自定义的View 中绘制和渲染由直线和曲线组成的路径。你可以在初始化的时候,直接为你的UIBezierPath 指定一个几何图形。 路径可以是简单的几何图形例如: 矩形、椭圆、弧线之类的,也可以是相对比较复杂的由直线和曲线组成的多边形。当你定义完图形以后, 你可以使用额外的方法将你的路径直接绘制在当前的绘图上下文中。
UIBezierPath 是由几何路径和属性组成的,属性是用来在渲染阶段描绘几何路径的,比如线宽之类的东西。路径和属性是完全独立的,他们并不互相依赖,你可以分开分开去设置他们。一旦你以自己喜欢的方式配置了UIBezierPath 对象,你就可以调用方法通知UIBezierPath 在当前的绘图上下文中绘制图形了。因为创建、 配置、 渲染路径等操作,都是完全不同的步骤, 所以你可以在你的代码中非常容易的对UIBezierPath 对象进行复用。你甚至可以使用同一个UIBezierPath 对象去渲染同一个图形很多次,你也可以再多次渲染的间隔中,修改属性来渲染出不同样式的路径。
当你创建了一个空的UIBezierPath 对象时,currentPoint 这个属性是未定义的,你需要手动的去设置currentPoint 。 如果你希望在不绘制任何线条的情况下移动currentPoint ,你可以使用moveToPoint: 方法。其他的方法都会导致在你的路径中添加额外的直线或曲线。 所有构造路径相关的方法, 都会以当前路径的currentPoint 为起点,以你指定的endPoint 为终点进行绘制。 当完成绘制之后,会自动将新增的这条线的终点设置为UIBezierPath 对象的currentPoint 。 一个简单的UIBezierPath 可以包含许多的开放子路径和封闭子路径。调用closePath 方法将会闭合路径,它将会从currentPoint 到子路经的firstPoint 绘制一条直线。调用moveToPoint: 方法将会结束当前的子路径, 但是并不会自动闭合当前的自路径,并且会将currentPoint 移动到指定的点,也就是下一条绘制路径的起始点。UIBezierPath 中所有的自路径都会共享同样的绘图属性。如果你希望绘制一些子路径,但是不适用相同的绘图属性,那么你就只能创建很多的UIBezierPath 对象来承载每一条路径。 当你为UIBezierPath 对象配置完几何路径和绘图属性之后,你就可以使用stroke 和fill 方法在当前的绘图上下文中进行绘制了。stroke 方法将会使用当前的strokeColor 和绘图属性来描绘曲线的轮廓。同样的,fill 方法将会使用fillColor 来填充路径所围成的图形(使用UIColor 类方法来设置strokeColor 和fillColor )。 画图步骤使用UIBezierPath 画图步骤: 1、创建一个UIBezierPath 对象2、调用moveToPoint: 设置初始线段的起点3、添加线或者曲线去定义一个或者多个子路径4、改变UIBezierPath 对象跟绘图相关的属性。如,我们可以设置画笔的属性、填充样式等
创建方法介绍我们先看看UIBezierPath 类提供了哪些创建方式,这些都是工厂方法,直接使用即可。 创建并且返回一个新的UIBezierPath 对象 + (instancetype)bezierPath 通过一个矩形, 创建并且返回一个新的UIBezierPath 对象 /** * 该方法将会创建一个闭合路径, 起始点是 rect 参数的的 origin, 并且按照顺时针针方向添加直线, 最终形成矩形 * @param rect: 矩形路径的 Frame */+ (instancetype)bezierPathWithRect:(CGRect)rect 通过一个指定的矩形中的椭圆形, 创建并且返回一个新的UIBezierPath 对象 /** * 该方法将会创建一个闭合路径, 该方法会通过顺时针的绘制贝塞尔曲线, 绘制出一个近似椭圆的形状. 如果 rect 参数指定了一个矩形, 那么该 UIBezierPath 对象将会描述一个圆形. * @param rect: 矩形路径的 Frame */+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect 根据一个圆角矩形, 创建并且返回一个新的UIBezierPath 对象 /** * 该方法将会创建一个闭合路径, 该方法会顺时针方向连续绘制直线和曲线. 当 rect 为正方形时且 cornerRadius 等于边长一半时, 则该方法会描述一个圆形路径. * @param rect:矩形路径的 Frame * @param cornerRadius:矩形的圆角半径 */+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius 根据一个圆角矩形, 创建并且返回一个新的UIBezierPath 对象 /** * 该方法将会创建一个闭合路径, 该方法会顺时针方向连续绘制直线和曲线. * @param rect:矩形路径的 Frame * @param corners:UIRectCorner 枚举类型, 指定矩形的哪个角变为圆角 * @param cornerRadii:矩形的圆角半径 */+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii 通过一个圆弧, 创建并且返回一个新的UIBezierPath 对象 /** * 该方法会创建出一个开放路径, 创建出来的圆弧是圆的一部分. 在默认的坐标系统中, 开始角度 和 结束角度 都是基于单位圆的(看下面这张图). 调用这个方法之后, currentPoint 将会设置为圆弧的结束点. * 举例来说: 指定其实角度为0, 指定结束角度为π, 设置 clockwise 属性为 YES, 将会绘制出圆的下半部分. * 然而当我们不修改起始角度 和 结束角度, 我们仅仅将 clockwise 角度设置为 NO, 则会绘制出来一个圆的上半部分. * @param center:圆心 * @param radius:半径 * @param startAngle:起始角度 * @param endAngle:结束角度 * @param clockwise:是否顺时针绘制 */+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise 通过一个CGPath , 创建并且返回一个新的UIBezierPath 对象 + (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath 下面我们一一介绍其用途。 + (instancetype)bezierPath 这个使用比较多,因为这个工厂方法创建的对象,我们可以根据我们的需要任意定制样式,可以画任何我们想画的图形。 + (instancetype)bezierPathWithRect:(CGRect)rect 这个工厂方法根据一个矩形画贝塞尔曲线。 + (instancetype)bezierPathWithOvalInRect:(CGRect)rect 这个工厂方法根据一个矩形画内切曲线。通常用它来画圆或者椭圆。 + (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius + (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii 第一个工厂方法是画矩形,但是这个矩形是可以画圆角的。第一个参数是矩形,第二个参数是圆角大小。 第二个工厂方法功能是一样的,但是可以指定某一个角画成圆角。像这种我们就可以很容易地给UIView 扩展添加圆角的方法了。 + (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise 这个工厂方法用于画弧,参数说明如下:center : 弧线中心点的坐标 radius : 弧线所在圆的半径startAngle : 弧线开始的角度值endAngle : 弧线结束的角度值clockwise : 是否顺时针画弧线 温馨提示我们下面的代码都是在自定义的BezierPathView 类中下面的方法中调用: - (void)drawRect:(CGRect)rect 了解坐标 画三角形#pragma mark - 画三角形- (void)drawTrianglePath{ UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(20, 20)]; [path addLineToPoint:CGPointMake(self.frame.size.width - 40, 20)]; [path addLineToPoint:CGPointMake(self.frame.size.width / 2, self.frame.size.height - 20)]; // 最后的闭合线是可以通过调用closePath方法来自动生成的,也可以调用-addLineToPoint:方法来添加 // [path addLineToPoint:CGPointMake(20, 20)]; [path closePath]; // 设置线宽 path.lineWidth = 1.5; // 设置填充颜色 UIColor *fillColor = [UIColor redColor]; [fillColor set]; [path fill]; // 设置画笔颜色 UIColor *strokeColor = [UIColor greenColor]; [strokeColor set]; // 根据我们设置的各个点连线 [path stroke];} 我们设置画笔颜色通过set 方法: UIColor *strokeColor = [UIColor greenColor];[strokeColor set]; 如果我们需要设置填充颜色,比如这里设置为绿色,那么我们需要在设置画笔颜色之前先设置填充颜色,否则画笔颜色就被填充颜色替代了。也就是说,如果要让填充颜色与画笔颜色不一样,那么我们的顺序必须是先设置填充颜色再设置画笔颜色。如下,这两者顺序不能改变。因为我们设置填充颜色也是跟设置画笔颜色一样调用UIColor的-set方法。 // 设置填充颜色UIColor *fillColor = [UIColor redColor];[fillColor set];[path fill];// 设置画笔颜色UIColor *strokeColor = [UIColor greenColor];[strokeColor set]; 画矩形#pragma mark - 画矩形- (void)drawRectPath{ UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40)]; path.lineWidth = 1.5; path.lineCapStyle = kCGLineCapRound; path.lineJoinStyle = kCGLineJoinBevel; // 设置填充颜色 UIColor *fillColor = [UIColor redColor]; [fillColor set]; [path fill]; // 设置画笔颜色 UIColor *strokeColor = [UIColor greenColor]; [strokeColor set]; // 根据我们设置的各个点连线 [path stroke];} lineCapStyle 属性是用来设置线条拐角帽的样式的,其中有三个选择:
/* Line cap styles. */typedef CF_ENUM(int32_t, CGLineCap) { kCGLineCapButt, kCGLineCapRound, kCGLineCapSquare}; 其中,第一个是默认的,第二个是轻微圆角,第三个正方形。
lineJoinStyle 属性是用来设置两条线连结点的样式,其中也有三个选择:
/* Line join styles. */typedef CF_ENUM(int32_t, CGLineJoin) { kCGLineJoinMiter, kCGLineJoinRound, kCGLineJoinBevel}; 其中,第一个是默认的表示斜接,第二个是圆滑衔接,第三个是斜角连接。
画圆我们可以使用bezierPathWithOvalInRect: 方法来画圆,当我们传的rect 参数是一下正方形时,画出来的就是圆。 #pragma mark - 画圆- (void)drawCiclePath{ // 传的是正方形,因此就可以绘制出圆了 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.width - 40)]; // 设置填充颜色 UIColor *fillColor = [UIColor redColor]; [fillColor set]; [path fill]; // 设置画笔颜色 UIColor *strokeColor = [UIColor greenColor]; [strokeColor set]; // 根据我们设置的各个点连线 [path stroke];} 注意:要画圆,我们需要传的rect 参数必须是正方形哦!
画椭圆前面我们已经画圆了,我们可以使用bezierPathWithOvalInRect: 方法来画圆,当我们传的rect 参数是一下正方形时,画出来的就是圆。那么我们要是不传正方形,那么绘制出来的就是椭圆了。 #pragma mark - 画椭圆- (void)drawOvalPath{ // 传的是不是正方形,因此就可以绘制出椭圆圆了 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20, 20, self.frame.size.width - 80, self.frame.size.height - 40)]; // 设置填充颜色 UIColor *fillColor = [UIColor redColor]; [fillColor set]; [path fill]; // 设置画笔颜色 UIColor *strokeColor = [UIColor greenColor]; [strokeColor set]; // 根据我们设置的各个点连线 [path stroke];} 画圆角矩形+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii 第一个工厂方法是画矩形,但是这个矩形是可以画圆角的。第一个参数是矩形,第二个参数是圆角大小。 第二个工厂方法功能是一样的,但是可以指定某一个角画成圆角。像这种我们就可以很容易地给UIView 扩展添加圆角的方法了。 #pragma mark - 画带圆角的矩形- (void)drawRoundedRectPath{ UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) byRoundingCorners:UIRectCornerTopRight cornerRadii:CGSizeMake(20, 20)]; // 设置填充颜色 UIColor *fillColor = [UIColor redColor]; [fillColor set]; [path fill]; // 设置画笔颜色 UIColor *strokeColor = [UIColor greenColor]; [strokeColor set]; // 根据我们设置的各个点连线 [path stroke];} 如果要画只有一个角是圆角,那么我们就修改创建方法: UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, self.frame.size.width - 40, self.frame.size.height - 40) byRoundingCorners:UIRectCornerTopRight cornerRadii:CGSizeMake(20, 20)]; 其中第一个参数一样是传了个矩形,第二个参数是指定在哪个方向画圆角,第三个参数是一个CGSize 类型,用来指定水平和垂直方向的半径的大小。看下效果图: 画弧画弧前,我们需要了解其参考系,如下图: #pragma mark - 画弧- (void)drawARCPath{ CGPoint center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2); UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:100 startAngle:0 endAngle:((M_PI * 135)/ 180) clockwise:YES]; path.lineCapStyle = kCGLineCapRound; path.lineJoinStyle = kCGLineJoinRound; path.lineWidth = 5.0; UIColor *strokeColor = [UIColor redColor]; [strokeColor set]; [path stroke];} 我们要明确一点,画弧参数startAngle 和endAngle 使用的是弧度,而不是角度,因此我们需要将常用的角度转换成弧度。对于效果图中,我们设置弧的中心为控件的中心,起点弧度为0,也就是正东方向,而终点是135度角的位置。如果设置的clockwise:YES 是逆时针方向绘制,如果设置为NO ,效果如下: 画二次贝塞尔曲线先来学习一下关于控制点,如下图: 画二次贝塞尔曲线,是通过调用此方法来实现的: - (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint 参数说明:endPoint: 终端点controlPoint: 控制点,对于二次贝塞尔曲线,只有一个控制点
#pragma mark - 画二次贝塞尔曲线- (void)drawSecondBezierPath{ UIBezierPath *path = [UIBezierPath bezierPath]; // 首先设置一个起始点 [path moveToPoint:CGPointMake(20, self.frame.size.height - 100)]; // 添加二次曲线 [path addQuadCurveToPoint:CGPointMake(self.frame.size.width - 20, self.frame.size.height - 100) controlPoint:CGPointMake(self.frame.size.width / 2, 0)]; path.lineCapStyle = kCGLineCapRound; path.lineJoinStyle = kCGLineJoinRound; path.lineWidth = 5.0; UIColor *strokeColor = [UIColor redColor]; [strokeColor set]; [path stroke];} 画二次贝塞尔曲线的步骤: 1、先设置一个起始点,也就是通过moveToPoint: 设置2、调用addQuadCurveToPoint:controlPoint: 方法设置终端点和控制点,以画二次曲线
在效果图中,拱桥左边的起始点就是我们设置的起始点,最右边的终点,就是我们设置的终端点,而我们设置的控制点为(width / 2, 0) 对应于红色矩形中水平方向在正中央,而垂直方向在最顶部。这个样式看起来很像sin 或者cos 函数吧?这两个只是特例而已,其实可以画任意图形,只是想不到,没有做不到的。 画三次贝塞尔曲线贝塞尔曲线必定通过首尾两个点,称为端点;中间两个点虽然未必要通过,但却起到牵制曲线形状路径的作用,称作控制点。关于三次贝塞尔曲线的控制器,看下图: 提示:其组成是起始端点+控制点1+控制点2+终止端点 如下方法就是画三次贝塞尔曲线的关键方法,以三个点画一段曲线,一般和moveToPoint: 配合使用。 - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2 实现代码是这样的: #pragma mark - 画三次贝塞尔曲线- (void)drawThirdBezierPath{ UIBezierPath *path = [UIBezierPath bezierPath]; // 设置起始端点 [path moveToPoint:CGPointMake(20, 150)]; [path addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(160, 0) controlPoint2:CGPointMake(160, 250)]; path.lineCapStyle = kCGLineCapRound; path.lineJoinStyle = kCGLineJoinRound; path.lineWidth = 5.0; UIColor *strokeColor = [UIColor redColor]; [strokeColor set]; [path stroke];} 我们需要注意,这里确定的起始端点为(20,150) ,终止端点为(300, 150) ,基水平方向是一致的。控制点1的坐标是(160,0) ,水平方向相当于在中间附近,这个参数可以调整。控制点2的坐标是(160,250) ,如果以两个端点的连线为水平线,那么就是250-150=100 ,也就是在水平线下100 。这样看起来就像一个sin 函数了。 CAShapeLayerCAShapeLayer 继承自CALayer ,因此,可使用CALayer 的所有属性。但是,CAShapeLayer 需要和贝塞尔曲线配合使用才有意义。官方文档
The shape layer draws a cubic Bezier spline in its coordinate space.The spline is described using a CGPath object and may have both fill and stroke components (in which case the stroke is composited over the fill). The shape as a whole is composited between the layer's contents and its first sublayer.
上面只是部分说明内容,由于较长,只放一部分出来。这里是说CAShapeLayer 是在其坐标系统内绘制贝塞尔曲线的。因此,使用CAShapeLayer 需要与UIBezierPath 一起使用。 主要属性// CAShapeLayer 绘制的路径@property(nullable) CGPathRef path;//路径中的填充颜色@property(nullable) CGColorRef fillColor;//填充规则@property(copy) NSString *fillRule;//画笔颜色(路径的颜色,边框颜色)@property(nullable) CGColorRef strokeColor;//这是一组范围值,路径绘制开始和结束的范围(0 -> 1)@property CGFloat strokeStart;@property CGFloat strokeEnd;//设置虚线显示的起点距离,设置为8,则显示长度8之后的线@property CGFloat lineDashPhase;//设置虚线线段的长度和空格的长度,@[@20,@30,@40,@50],画20空30画40空50@property(nullable, copy) NSArray *lineDashPattern;//以下属性参见 UIBezierPath 的介绍@property CGFloat lineWidth;@property CGFloat miterLimit;@property(copy) NSString *lineCap;@property(copy) NSString *lineJoin; 它有一个path 属性,而UIBezierPath 就是对CGPathRef 类型的封装,因此这两者配合起来使用才可以的哦! CAShapeLayer 是一个通过矢量图形而不是bitmap 来绘制的图层子类。可以指定颜色、线宽等属性,用CGPath 来定义想要绘制的图形,最后CAShapeLayer 就会自动渲染出来了。当然,你也可以用Core Graphics 直接向原始的CALyer 的内容中绘制一个路径drawLayer: inContext: ,
|
请发表评论