You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 10:55:06