UIBezierPath绘制椭圆/圆角矩形问题:线条突出+半径适配异常
解决方案
问题1:匹配目标形状的圆角半径
目标是类椭圆的圆角矩形,要让圆角弧度和矩形比例一致才协调。你的矩形宽320、高400,宽高比4:5,直接用宽高各一半的半径(width*0.5、height*0.5)就能生成完整椭圆;要是想要圆角稍小的矩形,就按比例缩小,比如用width*0.4、height*0.4,你可以对着目标图慢慢调整这个比例。
问题2:线条突出、形状不干净
这问题主要出在没处理stroke宽度、mask路径没组合对、路径和视图边界不匹配,改这几点就能解决:
- 创建路径时要向内缩
lineWidth/2,因为stroke是画在路径中间的,不缩的话一半线条会超出视图边界,要么被截断要么突出。 - 把注释掉的
backgroundPath.append(path)打开,这样mask用evenOdd规则才能把中间区域挖空,和边框对应上。 - 别用固定的
preferedSize,改用视图的bounds,布局变化时形状才会跟着适配。 - 给shapeLayer和maskLayer都设好frame为视图bounds,避免路径位置跑偏。
修改后的代码
override func layoutSubviews() { super.layoutSubviews() layer.sublayers?.forEach { $0.removeFromSuperlayer() } // 路径向内缩,给stroke留空间 let insetRect = bounds.insetBy(dx: lineWidth/2, dy: lineWidth/2) let path = makePath(rect: insetRect) path.lineJoinStyle = .round path.lineCapStyle = .round let shapeLayer = CAShapeLayer() shapeLayer.frame = bounds shapeLayer.shouldRasterize = true shapeLayer.rasterizationScale = UIScreen.main.scale shapeLayer.lineJoin = .round shapeLayer.path = path.cgPath shapeLayer.strokeColor = strokeColor.cgColor shapeLayer.lineWidth = lineWidth shapeLayer.lineCap = .round shapeLayer.fillColor = UIColor.clear.cgColor // 只显示边框,填充透明 layer.addSublayer(shapeLayer) layer.backgroundColor = overlayColor.cgColor // 组合路径实现中间挖空 let backgroundPath = UIBezierPath(rect: bounds) backgroundPath.append(path) // 取消注释,把中间路径加进去 let maskLayer = CAShapeLayer() maskLayer.frame = bounds maskLayer.shouldRasterize = true maskLayer.rasterizationScale = UIScreen.main.scale maskLayer.fillRule = .evenOdd maskLayer.path = backgroundPath.cgPath layer.mask = maskLayer addAdditionalLayersIfNeeded(bounds) // 传bounds而非rect } override func makePath(rect: CGRect) -> UIBezierPath { // 0.5是完整椭圆,0.4是稍小圆角,自己调比例匹配目标 let radiusRatio: CGFloat = 0.5 let cornerRadii = CGSize(width: rect.width * radiusRatio, height: rect.height * radiusRatio) return UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: cornerRadii) }
额外提示
- 要是必须用固定尺寸的形状,就把
insetRect改成preferedSize.insetBy(dx: lineWidth/2, dy: lineWidth/2),同时把shapeLayer和maskLayer的frame设为preferedSize,但还是建议用bounds适配布局更稳妥。 - 要是线条还有锯齿,直接关掉
shouldRasterize,有时候开光栅化反而会弄巧成拙,系统自带的抗锯齿就够了。
内容的提问来源于stack exchange,提问作者iamIcarus
相关产品推荐
相关产品推荐

