CAShapeLayer内部添加图片失败问题咨询及实现方案求助
CAShapeLayer内部添加图片失败问题咨询及实现方案求助
哥们,我仔细看了你的代码,发现几个导致系统图标不显示的关键问题,给你梳理下并附上可行的修改方案:
问题分析
- circularShapeLayer的bounds未正确初始化:你只给
circularShapeLayer设置了path,但没设置它的bounds,默认情况下它的bounds是CGRectZero,所以你给systemImageView.frame赋值为circularShapeLayer.bounds时,图片视图的尺寸是0,自然看不到。 - UIImageView的contentMode未配置:系统图标(SF Symbols)需要合适的contentMode来保证显示正常,默认的
contentMode可能导致图标被压缩或不显示。 - 图层层级的问题:直接把
UIImageView.layer添加到CAShapeLayer里,不如将UIImageView作为当前View的子视图来管理,这样布局和更新会更直观稳定。
修改后的完整代码
import Foundation import UIKit @IBDesignable class PlainHorizontalProgressBar: UIView { @IBInspectable var color: UIColor = .gray { didSet { setNeedsDisplay() } } var progress: CGFloat = 0 { didSet { setNeedsDisplay() } } var circularShapeColor: UIColor = .blue { didSet { setNeedsDisplay() } } private let progressLayer = CALayer() private let backgroundMask = CAShapeLayer() private let circularShapeLayer = CAShapeLayer() // Create an UIImageView for the system image private let systemImageView = UIImageView() override init(frame: CGRect) { super.init(frame: frame) circularShapeColor = UIColor.systemOrange setupLayers() } required init?(coder: NSCoder) { super.init(coder: coder) circularShapeColor = UIColor.systemOrange setupLayers() } private func setupLayers() { layer.addSublayer(progressLayer) layer.addSublayer(circularShapeLayer) // 将UIImageView作为当前View的子视图添加,而不是加到CAShapeLayer里 addSubview(systemImageView) // 配置图片视图的contentMode,保证图标正确显示 systemImageView.contentMode = .scaleAspectFit systemImageView.tintColor = .white // 先设置图片,避免后续重复设置 systemImageView.image = UIImage(systemName: "bolt.fill") } override func draw(_ rect: CGRect) { backgroundMask.path = UIBezierPath(roundedRect: rect, cornerRadius: rect.height * 0.75).cgPath layer.mask = backgroundMask let progressRect = CGRect(origin: .zero, size: CGSize(width: rect.width * progress, height: rect.height)) progressLayer.frame = progressRect progressLayer.backgroundColor = color.cgColor // Calculate the position and size of the circular shape let circularSize = CGSize(width: rect.height, height: rect.height) let circularOrigin = CGPoint(x: progressRect.maxX - circularSize.width / 2.0, y: (rect.height - circularSize.height) / 2.0) let circularRect = CGRect(origin: circularOrigin, size: circularSize) let circularPath = UIBezierPath(ovalIn: circularRect) // 设置circularShapeLayer的bounds和position,保证它的坐标系正确 circularShapeLayer.path = circularPath.cgPath circularShapeLayer.bounds = circularRect circularShapeLayer.position = CGPoint(x: circularRect.midX, y: circularRect.midY) circularShapeLayer.fillColor = circularShapeColor.cgColor // 更新图片视图的frame,让它正好覆盖圆形图层 systemImageView.frame = circularRect } }
额外优化建议
- 如果你的进度条需要动画更新,建议把
draw(_:)里的布局逻辑移到layoutSubviews()方法里,这样在视图尺寸变化时也能正确更新布局。 - 可以给
progress的设置加上范围限制(比如progress = max(0, min(1, newProgress))),避免进度值超出0-1的范围导致布局异常。
备注:内容来源于stack exchange,提问作者Saland
相关产品推荐
相关产品推荐

