如何实现UIBezierPath路径内部描边?CoreGraphics描边方向调整
嘿,这个问题我之前做自定义控件的时候踩过坑!默认情况下CoreGraphics的描边是把线条居中在路径上的——也就是说一半在路径内侧,一半在外侧。如果想让整个线条都缩到路径内部,有几个很实用的实现方法,我给你捋清楚:
方法1:裁剪+外扩路径描边
这个思路是利用裁剪区域限制绘制范围,让描边的外侧被“切掉”,只保留内侧部分。适合所有闭合路径,兼容iOS13以下系统。
步骤很简单:
- 先保存当前图形上下文状态(避免影响其他绘制)
- 把原路径设置为裁剪区域,这样后续只能在原路径内部绘制
- 创建一个比原路径外扩半个线条宽度的新路径
- 用完整的线条宽度描边这个外扩路径——此时描边的外侧会被裁剪掉,剩下的刚好是原路径内侧的线条
代码示例:
let originalPath = UIBezierPath(rect: CGRect(x: 20, y: 20, width: 100, height: 100)) let lineWidth: CGFloat = 10.0 guard let ctx = UIGraphicsGetCurrentContext() else { return } ctx.saveGState() defer { ctx.restoreGState() } // 设置原路径为裁剪区域 originalPath.addClip() // 外扩半个线条宽度(iOS13+可用offset方法,更精准) var expandedPath: UIBezierPath if #available(iOS 13.0, *) { expandedPath = originalPath.offset(by: lineWidth / 2)! } else { // iOS13以下可以用缩放替代(适合规则形状,比如矩形、圆形) let scale = 1 + lineWidth / originalPath.bounds.width expandedPath = UIBezierPath(bezierPath: originalPath) expandedPath.apply(CGAffineTransform(scaleX: scale, y: scale)) } // 描边外扩后的路径 expandedPath.lineWidth = lineWidth expandedPath.stroke()
方法2:内缩路径生成环形填充
如果你的目标是iOS13及以上系统,这个方法更直接——直接生成原路径的内缩版本,然后用原路径减去内缩路径得到环形区域,填充这个区域就等于实现了内侧描边。
好处是不需要裁剪,对不规则路径(比如带圆角、曲线的形状)适配更好,因为offset(by:)是沿着路径法线方向偏移的,不会变形。
代码示例:
let originalPath = UIBezierPath(rect: CGRect(x: 20, y: 20, width: 100, height: 100)) let lineWidth: CGFloat = 10.0 // 生成内缩完整线条宽度的路径(负数为内缩) guard let insetPath = originalPath.offset(by: -lineWidth) else { return // 路径太小无法内缩时做容错处理 } // 创建环形路径:原路径 + 内缩路径,使用奇偶填充规则 let strokeAreaPath = UIBezierPath() strokeAreaPath.append(originalPath) strokeAreaPath.append(insetPath) strokeAreaPath.usesEvenOddFillRule = true // 填充环形区域,效果和内侧描边完全一致 strokeAreaPath.fill()
注意事项
- 以上方法只适用于闭合路径,开放路径(比如一条直线)没有“内侧”的概念,默认的居中描边是唯一合理的表现。
- 对于特别复杂的路径(比如带交叉的不规则形状),可能需要手动遍历路径点计算内缩路径,但这种场景极少,前两种方法基本能覆盖绝大多数需求。
内容的提问来源于stack exchange,提问作者Sudhanshu Monga
相关产品推荐
相关产品推荐

