如何在UIView上绘制四边尺寸规格一致的虚线边框
问题原因
你当前实现四边虚线宽度不一致,核心是两个问题:
- 没有显式设置
CAShapeLayer的lineWidth属性,依赖系统默认值容易出现渲染差异 - 描边路径完全贴合视图bounds,而ShapeLayer的描边是沿路径中心线向两侧各延伸一半线宽的,路径外侧的半段线宽会落在视图边界外被裁剪;如果视图存在非整数frame、布局时机不对的情况,上下边和左右边被裁剪的程度不一致,就会出现粗细差异。
修复方法
核心调整点:
- 显式指定虚线的线宽
- 将绘制路径的矩形向内缩进线宽的1/2,让整个描边完全落在视图内部,不会被边界裁剪
- 在视图布局完成后更新虚线layer的尺寸,避免约束调整、横竖屏切换后边框错位
推荐在自定义视图的layoutSubviews方法中更新虚线配置,代码如下:
class CustomDashedView: UIView { private let dashedBorderLayer = CAShapeLayer() // 按需调整配置参数 private let config: (lineWidth: CGFloat, cornerRadius: CGFloat, dashLength: NSNumber, dashGap: NSNumber, color: UIColor) = ( lineWidth: 1, cornerRadius: 10, dashLength: 3, dashGap: 3, color: .blue ) override init(frame: CGRect) { super.init(frame: frame) setupBorderLayer() } required init?(coder: NSCoder) { super.init(coder: coder) setupBorderLayer() } private func setupBorderLayer() { dashedBorderLayer.fillColor = UIColor.clear.cgColor dashedBorderLayer.strokeColor = config.color.cgColor dashedBorderLayer.lineWidth = config.lineWidth dashedBorderLayer.lineJoin = .round dashedBorderLayer.lineDashPattern = [config.dashLength, config.dashGap] layer.addSublayer(dashedBorderLayer) } override func layoutSubviews() { super.layoutSubviews() // 向内缩进半线宽,避免描边被裁剪 let drawRect = bounds.insetBy(dx: config.lineWidth / 2, dy: config.lineWidth / 2) dashedBorderLayer.bounds = drawRect dashedBorderLayer.position = CGPoint(x: bounds.midX, y: bounds.midY) dashedBorderLayer.path = UIBezierPath(roundedRect: drawRect, cornerRadius: config.cornerRadius).cgPath } }
补充说明
- 如果不需要圆角,把
cornerRadius设为0即可,直边虚线同样能保证四边宽度完全一致 - 不要在视图布局完成前(比如
init、控制器viewDidLoad阶段)固定虚线layer的尺寸,此时视图的frame还不是最终渲染尺寸,容易出现错位、粗细异常问题 - 如果不自定义视图子类,在持有该视图的控制器中重写
viewDidLayoutSubviews方法,按照上述缩进逻辑更新虚线layer的path和尺寸即可 - 如果需要调整虚线的虚实比例,修改
lineDashPattern的数值即可,第一个值为实线段长度,第二个值为间隙长度
内容的提问来源于stack exchange,提问作者kb920
相关产品推荐
相关产品推荐

