技术求助:如何用UIKit实现顺时针百分比填充色的ImageView
UIKit实现带双色顺时针百分比填充的ImageView方案
给你几个可行的实现思路,都是基于UIKit原生组件的方案:
方案一:双层CAShapeLayer叠加
这种方式适合圆形或规则形状的ImageView:
- 先创建一个底层灰色Layer:用
CAShapeLayer绘制完整的目标形状(比如圆形),设置填充/描边色为未完成状态的灰色,作为背景层。 - 再创建一个上层彩色Layer:同样用
CAShapeLayer绘制相同形状,设置填充/描边色为完成状态的彩色,通过strokeEnd(描边模式)或path(填充模式)控制显示的百分比。比如描边模式下,把strokeStart设为0,strokeEnd设为进度值(如0.7代表70%),就能实现顺时针的部分填充。 - 将两个Layer添加到ImageView的
layer上,确保尺寸和位置与ImageView匹配。
方案二:双ImageView叠加+Mask遮罩
这种方式适配任意形状的ImageView,灵活性更高:
- 准备两个完全相同的ImageView:
- 底层ImageView:设置
tintColor为未填充状态的灰色,作为背景。 - 上层ImageView:设置
tintColor为填充状态的彩色,放在底层视图上方。
- 底层ImageView:设置
- 给上层ImageView添加
CAShapeLayer作为遮罩:根据进度值绘制顺时针的扇形(或对应形状的路径),只让上层ImageView的对应区域显示,剩余区域透出底层的灰色。 - 进度更新时,动态修改遮罩Layer的路径即可。
简单代码示例(圆形场景)
class ProgressImageView: UIImageView { var progress: CGFloat = 0 { didSet { updateMaskLayer() } } private let topImageView = UIImageView() override init(image: UIImage?) { super.init(image: image?.withRenderingMode(.alwaysTemplate)) setupSubviews() } required init?(coder: NSCoder) { super.init(coder: coder) setupSubviews() } private func setupSubviews() { // 底层灰色背景 self.tintColor = UIColor.lightGray // 上层彩色视图 topImageView.image = self.image?.withRenderingMode(.alwaysTemplate) topImageView.tintColor = UIColor.systemBlue topImageView.frame = self.bounds topImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.addSubview(topImageView) // 初始化遮罩Layer let maskLayer = CAShapeLayer() maskLayer.fillColor = UIColor.black.cgColor topImageView.layer.mask = maskLayer } private func updateMaskLayer() { guard let maskLayer = topImageView.layer.mask as? CAShapeLayer else { return } let center = CGPoint(x: bounds.midX, y: bounds.midY) let radius = min(bounds.width, bounds.height) / 2 // 从12点钟方向开始顺时针绘制扇形路径 let startAngle = -CGFloat.pi / 2 let endAngle = startAngle + 2 * CGFloat.pi * progress let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true) path.addLine(to: center) path.close() maskLayer.path = path.cgPath } }
方案三:重写draw(_ rect:)自定义绘制
如果需要更复杂的形状适配,可以自定义ImageView并重写绘制方法:
- 在
draw(_ rect:)中,先绘制未填充的灰色完整形状。 - 再根据进度值,用贝塞尔路径绘制顺时针的填充区域,填充彩色。
- 若要适配不规则图片,可以通过图片的alpha通道提取轮廓路径,再基于该路径生成填充区域。
注意事项
- 所有UI操作确保在主线程执行,避免卡顿。
- 若使用描边模式,可通过
lineCap属性设置进度端点的样式(如圆角)。 - 不规则形状的场景,可利用
UIImage的CGImage提取alpha通道生成路径。
内容的提问来源于stack exchange,提问作者Francesco Destino
相关产品推荐
相关产品推荐

