内容简介:本文参考此文参考我们在项目中会接触到一些曲线的绘制,最初接触这个概念是因为有一个在屏幕右边的按钮,因为贴着屏幕,按钮右边是没有圆角的,而左上和左下是圆角,类似:还没知道贝塞尔曲线绘制之前,我是直接用
本文参考此文参考
我们在项目中会接触到一些曲线的绘制,最初接触这个概念是因为有一个在屏幕右边的按钮,因为贴着屏幕,按钮右边是没有圆角的,而左上和左下是圆角,类似:
还没知道贝塞尔曲线绘制之前,我是直接用 _laborExplainButton.layer.cornerRadius = 33/2;
绘制一个四个角都是圆角的按钮,然后给出文字靠左属性 _laborExplainButton.titleLabel.textAlignment = NSTextAlignmentLeft;
设定按钮宽度时,多给出一段宽度,在用Masonary布局时让右边超出父视图,再慢慢调数值,让文字接近居中。
方法很笨,但是还算是实现了图片的效果(笑)。
但是往后出现的一些类似于tableView的紧密相连的cell的第一个cell左上和右上为圆角的需求,总不能再这样“投机”了,就开始学习到了用贝塞尔曲线实现。
本笔记将从苹果官方API:UIBezierPath.h文件的各种方法解释、介绍出发,介绍常用的一些方法和流程,再对具体案例做实现介绍,做一个从学到用的总结,不能做到所有方法方面都顾及,更深的更复杂的绘制实现还待后续学习补充。
一、UIBezierPath的概念
UIBezierPath是在iOS开发中绘制矢量图或者路径的时候会经常使用的一个部分,在UIKit里面是CoreGraphics对path的封装,使用UIBezierPath可以绘制直线、矩形、椭圆、不规则图形、多边形和贝塞尔曲线等,只要是能想到的线条都能画出来。
二、UIBezierPath.h内方法介绍
// 用来对某(几)个角进行贝塞尔绘制 typedef NS_OPTIONS(NSUInteger, UIRectCorner) { UIRectCornerTopLeft = 1 << 0, UIRectCornerTopRight = 1 << 1, UIRectCornerBottomLeft = 1 << 2, UIRectCornerBottomRight = 1 << 3, UIRectCornerAllCorners = ~0UL }; // 初始化无形装的贝塞尔曲线 + (instancetype)bezierPath; // 初始化矩形贝塞尔曲线 + (instancetype)bezierPathWithRect:(CGRect)rect; // 绘制椭圆(圆形)贝塞尔曲线 + (instancetype)bezierPathWithOvalInRect:(CGRect)rect; // 绘制含有圆角的贝塞尔曲线 + (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius // 绘制可选择圆角方位的贝塞尔曲线 + (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii; // 绘制圆弧曲线 + (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise; // 根据CGPathRef绘制贝塞尔曲线 + (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath; - (instancetype)init NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER; // CGPath可以理解为图形的路径,拿到CGPath - (CGPathRef)CGPath NS_RETURNS_INNER_POINTER CF_RETURNS_NOT_RETAINED; // Path construction // 贝塞尔曲线开始的点 - (void)moveToPoint:(CGPoint)point; // 添加直线到该点 - (void)addLineToPoint:(CGPoint)point; // 添加二次曲线到该点 - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2; // 添加曲线到该点 - (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint; // 添加圆弧 - (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0); // 闭合曲线 - (void)closePath; // 移除所有曲线的点 - (void)removeAllPoints; // 路径拼接 - (void)appendPath:(UIBezierPath *)bezierPath; // 返回一个与当前路径相反的新的贝塞尔路径对象 - (UIBezierPath *)bezierPathByReversingPath NS_AVAILABLE_IOS(6_0); // 路径进行仿射变换 - (void)applyTransform:(CGAffineTransform)transform; // Path info // 只读类型,路径上是否有有效的元素 @property(readonly,getter=isEmpty) BOOL empty; // 和view的bounds是不一样的,它获取path的X坐标、Y坐标、宽度,但是高度为0 @property(nonatomic,readonly) CGRect bounds; // 当前path的位置,可以理解为path的终点 @property(nonatomic,readonly) CGPoint currentPoint; // 路径是否包含点point - (BOOL)containsPoint:(CGPoint)point; // Drawing properties // 边框高度 @property(nonatomic) CGFloat lineWidth; // 端点类型 @property(nonatomic) CGLineCap lineCapStyle; // 线条连接类型 @property(nonatomic) CGLineJoin lineJoinStyle; // 线条最大宽度最大限制 @property(nonatomic) CGFloat miterLimit; // Used when lineJoinStyle is kCGLineJoinMiter // 绘制的精度,默认为0.6,精度越大需要处理的时间越长 @property(nonatomic) CGFloat flatness; // 单双数圈规则是否用于绘制路径,默认是NO @property(nonatomic) BOOL usesEvenOddFillRule; // Default is NO. When YES, the even-odd fill rule is used for drawing, clipping, and hit testing. // 设置线型 - (void)setLineDash:(nullable const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase; // 检索线型 - (void)getLineDash:(nullable CGFloat *)pattern count:(nullable NSInteger *)count phase:(nullable CGFloat *)phase; // Path operations on the current graphics context // 填充贝塞尔曲线内部 - (void)fill; // 绘制贝塞尔曲线边框 - (void)stroke; // These methods do not affect the blend mode or alpha of the current graphics context // 过于复杂 - (void)fillWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha; - (void)strokeWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha; // 修改当前图形上下文的绘图区域可见,随后的绘图操作导致呈现内容只有发生在指定路径的填充区域 - (void)addClip; 复制代码
三、UIBezierPath的使用
UIBezierPath是对CGPathRef的封装,它提供了CGPath属性使我们在开发过程中获取底层的path,在创建矢量图形的时候,把图形拆解成一条或者多条线段,然后拼接在一起,每条线段的终点都是下一条线段的起点,这就是大概的实现思路。具体步骤如下:
1、创建一个UIBezierPath对象;
2、用moveToPoint:方法设置初始线段的起点;
3、添加线段,定义一个或者多个子路径;
4、修改UIBezierPathUIBezierPath的绘图部分的相关属性;
一个cell顶部两角切圆角的简单实现:
效果图:
图片是个UIImageView,起初对背景的白色view切了四个角的圆角,发现这个UIImageView还是四角尖尖,再对UIImageView切圆角,变成了四角圆圆....所以,在对背景view切好四个角圆角后,我们还要用贝塞尔,切UIImageView的上两个角圆角:
但是,我用的是Masonary布局,在懒加载中写贝塞尔相关属性,并不能实现,因为一开始不能得到UIImageView的布局,所以研究了一番,我们在 - (void)layoutSubviews;
方法中才去写切圆角操作,这个方法是在布局完之后会走一次的,很好的解决了取不到范围的问题。
具体:
- (void)layoutSubviews{ [super layoutSubviews]; // 切上上两角圆角 UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.coverImageView.bounds byRoundingCorners: UIRectCornerTopLeft|UIRectCornerTopRight cornerRadii:CGSizeMake(5, 5)]; CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init]; // frame为UIImageView的bounds maskLayer.frame = self.coverImageView.bounds; maskLayer.path = maskPath.CGPath; self.coverImageView.layer.mask = maskLayer; } 复制代码
项目中其他类似的情况都触类旁通,使用此方法解决。
这里其实是UIBezierPath结合其他layer使用。 原则上使用UIBezierPath主要只是画出形状或画出一个图形的路径path,但是它也可以配合其他的layer使用(CAShapeLayer,CAGradientLayer等),layer可以添加动画,所以UIBezierPath结合layer使用效果会更棒。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- canvas学习笔记-绘制简单路径
- opencv自带例子学习-几何图形的绘制1
- 老司机专为测试新手绘制的学习selenium路线图(基础普及篇)!
- 基于Vue的任务节点图绘制插件节点可拖拽多连线样式(vue-task-node)可用于机器学习,UML,及事物...
- ViewGroup 默认顺序绘制子 View,如何修改?什么场景需要修改绘制顺序?
- Shader 绘制基础图形
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。