如何修复viewforarow中addArrowToView无法显示UIBezierPath三角形的问题?
问题原因与修复方案
核心问题
- 调用时机错误:你在给
arrowContainerView添加约束前就调用了addArrowToView,此时视图还未完成布局,arrowContainerView.bounds是初始的CGRect.zero,导致计算出的三角形路径宽高均为0,自然无法显示。 - 额外隐患:约束里使用
view.bounds.width / 3作为宽度常量,若调用viewforarow时父视图布局也未完成,这个宽度值同样会出错。
修复方案
方法一:强制布局后再绘制箭头
先激活约束,强制视图完成布局以获取正确的bounds,再执行箭头绘制:
func addArrowToView(_ view: UIView) { let arrowLayer = CAShapeLayer() let trianglePath = UIBezierPath() let width = view.bounds.width let height = view.bounds.height trianglePath.move(to: CGPoint(x: width - 2, y: height/2)) trianglePath.addLine(to: CGPoint(x: width - 5, y: height )) trianglePath.addLine(to: CGPoint(x: width - 5, y: 0)) trianglePath.close() arrowLayer.path = trianglePath.cgPath arrowLayer.fillColor = UIColor.red.cgColor arrowLayer.strokeColor = UIColor.clear.cgColor view.layer.addSublayer(arrowLayer) } func viewforarow(_ view: UIView) { let arrowContainerView = UIView() arrowContainerView.backgroundColor = UIColor.purple arrowContainerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(arrowContainerView) // 先激活所有约束 NSLayoutConstraint.activate([ arrowContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), arrowContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor), // 改用相对宽度,避免依赖未确定的bounds arrowContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/3), arrowContainerView.heightAnchor.constraint(equalTo: view.heightAnchor) ]) // 强制完成布局,获取正确的bounds arrowContainerView.layoutIfNeeded() // 此时再绘制箭头 addArrowToView(arrowContainerView) }
方法二:让箭头自动适配视图尺寸变化
如果视图后续可能改变尺寸(比如屏幕旋转),方法一的箭头不会跟着更新,推荐子类化UIView,在布局更新时自动刷新箭头路径:
// 自定义带箭头的容器视图 class ArrowContainerView: UIView { private let arrowLayer = CAShapeLayer() override init(frame: CGRect) { super.init(frame: frame) setupArrowLayer() } required init?(coder: NSCoder) { super.init(coder: coder) setupArrowLayer() } private func setupArrowLayer() { arrowLayer.fillColor = UIColor.red.cgColor arrowLayer.strokeColor = UIColor.clear.cgColor layer.addSublayer(arrowLayer) } override func layoutSubviews() { super.layoutSubviews() // 每次布局更新时重新计算箭头路径 let width = bounds.width let height = bounds.height let trianglePath = UIBezierPath() trianglePath.move(to: CGPoint(x: width - 2, y: height/2)) trianglePath.addLine(to: CGPoint(x: width - 5, y: height )) trianglePath.addLine(to: CGPoint(x: width - 5, y: 0)) trianglePath.close() arrowLayer.path = trianglePath.cgPath } } // 使用自定义视图 func viewforarow(_ view: UIView) { let arrowContainerView = ArrowContainerView() arrowContainerView.backgroundColor = UIColor.purple arrowContainerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(arrowContainerView) NSLayoutConstraint.activate([ arrowContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), arrowContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor), arrowContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/3), arrowContainerView.heightAnchor.constraint(equalTo: view.heightAnchor) ]) }
内容的提问来源于stack exchange,提问作者user8058965
相关产品推荐
相关产品推荐

