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

Swift UIKit中使用相同frame绘制线条显示不一致问题求解

问题核心原因

  • 生命周期时机错误:viewDidLoad方法调用时,Storyboard中通过AutoLayout约束配置的视图还没有完成最终的布局适配,此时读取的TopView.frame是Storyboard设计时的预设尺寸,不是运行时适配当前设备的真实尺寸,后续AutoLayout更新TopView的frame后,你提前创建的贝塞尔路径不会自动同步更新。
  • 坐标系使用错误:你在Vvp函数中初始化子视图时用了inView.frame,frame是视图相对于其父视图坐标系的数值,而子视图的frame需要相对于它的直接父视图(也就是你传入的inView)的自身坐标系,应该使用inView.bounds来初始化子视图的frame,否则子视图的位置会出现偏移。

修复方案

  1. 将图层绘制、子视图尺寸调整的逻辑移到viewDidLayoutSubviews中执行,这个方法会在AutoLayout完成所有视图布局后触发,此时读取的frame/bounds是运行时的正确值。注意要避免重复添加子视图和图层,建议把需要复用的图层、子视图声明为控制器的属性。
  2. 子视图初始化、内部坐标计算统一使用父视图的bounds属性,不要使用frame。

修正后代码示例

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var TopView: UIView!
    @IBOutlet weak var MiddleView: UIView!
    @IBOutlet weak var BottomView: UIView!
    
    // 声明为属性避免重复添加
    private var redShapeLayer: CAShapeLayer?
    private var customSubview: UIView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // 只做初始化添加,不做尺寸相关计算
        let t = Vvp(inView: TopView)
        TopView.addSubview(t)
        customSubview = t
        
        let shapeLayer = CAShapeLayer()
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.fillColor = UIColor.red.cgColor
        shapeLayer.lineWidth = 1.0
        TopView.layer.addSublayer(shapeLayer)
        redShapeLayer = shapeLayer
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // 布局完成后再更新尺寸相关的路径、frame
        guard let redShapeLayer, let customSubview else { return }
        
        // 更新红色图层路径
        let redBezierPath = UIBezierPath()
        redBezierPath.move(to: CGPoint(x: 0, y: 0))
        redBezierPath.addLine(to: CGPoint(x: TopView.bounds.maxX, y: 0))
        redBezierPath.close()
        redShapeLayer.path = redBezierPath.cgPath
        
        // 更新自定义子视图的frame和内部路径
        customSubview.frame = TopView.bounds
        if let blueLayer = customSubview.layer.sublayers?.first as? CAShapeLayer {
            let blueBezierPath = UIBezierPath()
            blueBezierPath.move(to: CGPoint(x: 0, y: 0))
            blueBezierPath.addLine(to: CGPoint(x: TopView.bounds.maxX, y: 0))
            blueBezierPath.close()
            blueLayer.path = blueBezierPath.cgPath
        }
    }
}
func Vvp(inView: UIView)-> UIView {
    // 用bounds初始化子视图frame
    let viewWithBeizer = UIView(frame: inView.bounds)
    let bezierPath = UIBezierPath()
    bezierPath.move(to: CGPoint(x: 0, y: 0))
    bezierPath.addLine(to: CGPoint(x: inView.bounds.maxX, y: 0))
    bezierPath.close()
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = bezierPath.cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.fillColor = UIColor.blue.cgColor
    shapeLayer.lineWidth = 1.0
    viewWithBeizer.layer.addSublayer(shapeLayer)
    return viewWithBeizer
}

内容的提问来源于stack exchange,提问作者Alek Szczęsnowicz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 21:54:04