一. 背景
项目中经常遇到需要给按钮或者视图设置0.5
的边框,因此习惯通过layer.borderWidth
的来设置,但设置出来,会发现上下边框有点不均匀,明显左上部分比较细,右下部分比较粗。

这个图片上传到掘金,有点失真,但实际截图确实是左上边框细,右下边框粗。
二. 分析
为什么layer.borderWidth
设置了0.5
,会出现边框不均匀现象,左上边框细,右下边框粗,但设置为1
,就是正常的。
这个问题的原因:
- 亚像素渲染的方向性偏差
-
iOS 渲染引擎(如 Core Animation
)在处理小数像素(如缩放后的0.5px
)时,对不同边缘的抗锯齿策略不同:- 左上边缘 (起始边缘):被视为"布局原点",系统可能优先丢弃小于
1
物理像素的部分,导致视觉上变细或断裂。 - 右下边缘(结束边缘):作为"合成终点",抗锯齿算法会混合相邻像素的颜色值,使边缘显得更粗或模糊。
- 左上边缘 (起始边缘):被视为"布局原点",系统可能优先丢弃小于
-
物理像素不可分割性:缩放后的边框实际物理像素可能为小数(如
DPR
=3 时为1.5px
),系统需四舍五入处理,加剧方向差异。
Retina 屏幕的设备像素比(DPR)通常为 2 或 3(如 iPhone 13 的 DPR=3, iPhone6 的 DPR=2)
- 图层合成的坐标对齐问题
- 若父视图的坐标或尺寸为浮点数(如自动布局计算
100.5pt
),子图层的缩放会触发亚像素渲染,放大左上/右下的差异。 - 独立图层缩放后,其像素边界可能与屏幕物理像素网格未对齐,导致部分区域被抗锯齿丢弃(左上),部分混合强化(右下)。
- 抗锯齿算法的局限性
- 斜边(如圆角)的渲染依赖高斯滤波等抗锯齿技术,起始点(左上)滤波权重较低,结束点(右下)权重较高,造成粗细差异。
了解了layer.borderWidth
设置0.5
,会出现边框不均匀现象原因后,而设置为1
之所以不会出现这种情况,主要原因是1
得到的实际物理像素始终为整数,不存在丢弃的现象。
那有什么好的治理方案,可以解决这个问题呢?
答案是通过CAShapeLayer
矢量路径绘制用矢量路径替代边框,精确控制每一条边。
CAShapeLayer 的矢量绘制原理
- 数学路径描述(矢量图形)
CAShapeLayer 通过 CGPath(如 UIBezierPath 创建的路径)定义形状,路径由数学公式(贝塞尔曲线)描述,而非像素位图。渲染时,系统根据当前屏幕的物理分辨率(如 Retina 屏的 DPR=2 或 3)动态计算路径的物理像素位置,确保边缘始终与屏幕物理像素网格对齐。
- 抗锯齿的均匀性
矢量路径在光栅化(转换为像素)时,系统会对整个路径边缘应用全局抗锯齿算法(如 Lanczos 采样),而非仅针对特定方向(如左上/右下边缘)。这消除了因方向性抗锯齿策略导致的粗细差异。
- 独立于图层变换
即使对 CAShapeLayer 进行 3D 变换(旋转、缩放),路径仍保持平滑无像素化,因为矢量图形会在变换后重新采样,而非直接拉伸位图。

因此使用CAShapeLayer
加上UIBezierPath
绘制路径,可以很好的解决这个0.5
边框不均匀问题。
三. 治理
使用CAShapeLayer
加上UIBezierPath
绘制路径,可以很好的解决这个0.5
边框不均匀问题。
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:button.bounds cornerRadius:5].CGPath;
shapeLayer.strokeColor = [UIColor blackColor].CGColor;
shapeLayer.lineWidth = 0.5; // 直接设置0.5px(仅CAShapeLayer支持)
shapeLayer.fillColor = nil;
button.layer addSublayer:shapeLayer\];
效果图:
