有人用 swift 框架理解这个悖论吗?

does anybody understand this paradox with swift frames?

在 UIKIT 中,我有两个 uiview 的主视图和 uiview,在顶部安装了故事板,主视图的 1/3 高。

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var TopView: UIView!
@IBOutlet weak var MiddleView: UIView!
@IBOutlet weak var BottomView: UIView!



override func viewDidLoad() {
    super.viewDidLoad()

    let t = Vvp(inView: TopView)
    TopView.addSubview(t)
    
    let bezierPath = UIBezierPath()
    bezierPath.move(to: CGPoint(x: 0, y: 0))
    bezierPath.addLine(to: CGPoint(x: TopView.frame.maxX, y: 0))
    
    bezierPath.close()

   
let shapeLayer = CAShapeLayer()

        shapeLayer.path = bezierPath.cgPath

        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.fillColor = UIColor.red.cgColor
        shapeLayer.lineWidth = 1.0
    TopView.layer.addSublayer(shapeLayer)
    
}

}

第二个视图:

func Vvp(inView: UIView)-> UIView {

let viewWithBeizer = UIView(frame: inView.frame)

    let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: 0, y: 0))
bezierPath.addLine(to: CGPoint(x: inView.frame.maxX, y: 0))
    
    bezierPath.close()

   
let shapeLayer = CAShapeLayer()
        shapeLayer.path = bezierPath.cgPath

        // apply other properties related to the path
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.blue.cgColor
        shapeLayer.lineWidth = 1.0
        viewWithBeizer.layer.addSublayer(shapeLayer)
        return viewWithBeizer

    

}

两个视图都使用相同的框架,在情节提要中所有边框都为零 为什么线条不一样?

我认为这是 iPod touch 7' 模拟器的错误 - 另一个模拟器代码运行良好。您可以在下面看到我的问题中的代码,其中我将 2px 添加到红线。

问题与画线的位置无关...

问题是当您应该使用 bounds 时,您指的是 frame您在自动布局配置视图之前设置框架。

根据您的屏幕截图,您正在基于 iPhone 带有缺口的模型在 Storyboard 中布置您的视图...因此,在 viewDidLoad() 中,您的 TopView 具有在情节提要中设置的框架。

这是在 Storyboard 中使用 iPhone 13 Pro 时的样子:

如您所见,即使黄色的TopView被限制在安全区域的顶部,它的Y位置却是44。因此,您 func Vvp(inView: UIView) 中的代码将 Frame Y 位置设置为 44,而不是零。

如果在viewDidLoad()末尾添加这4行:

    TopView.layer.addSublayer(shapeLayer)

    // move t (from Vvp(inView: TopView))
    //  40-pts to the right
    t.frame.origin.x += 40.0
    // give it an orange background color
    t.backgroundColor = .orange
    // allow it to show outside the bounds of TopView
    TopView.clipsToBounds = false
    // bring TopView to the front of the view hierarchy
    view.bringSubviewToFront(TopView)

iPad Touch 7th Gen 的输出如下所示:

如您所见,TopView 的子视图(橙色视图)比 TopView 大得多,并且显示在您指定的位置:距离 TopView 顶部 44 磅。

要按照您编写的方式使用代码,您需要调用该函数 - 以及 TopView 的 shapeLayer 代码 - 在控制器生命周期的后期......例如 viewDidLayoutSubviews()。但是,如果你这样做,你需要记住它会被多次调用(任何时候主视图发生变化,例如设备旋转),所以你要确保你不会重复添加新的子视图和图层.

这里是对您的代码的快速修改:

class ViewController: UIViewController {
    
    @IBOutlet weak var TopView: UIView!
    @IBOutlet weak var MiddleView: UIView!
    @IBOutlet weak var BottomView: UIView!

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        if TopView.subviews.count == 0 {
            // we haven't added the subview or shape layer,
            //  so let's do that here
        
            let t = Vvp(inView: TopView)
            TopView.addSubview(t)
            
            let bezierPath = UIBezierPath()
            bezierPath.move(to: CGPoint(x: 0, y: 0))
            bezierPath.addLine(to: CGPoint(x: TopView.frame.maxX, y: 0))
            
            let shapeLayer = CAShapeLayer()
            
            shapeLayer.path = bezierPath.cgPath
            
            shapeLayer.strokeColor = UIColor.red.cgColor
            shapeLayer.fillColor = UIColor.red.cgColor
            shapeLayer.lineWidth = 1.0
            TopView.layer.addSublayer(shapeLayer)
        }

    }
    
    func Vvp(inView: UIView)-> UIView {
        
        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))
        
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = bezierPath.cgPath
        
        // apply other properties related to the path
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.blue.cgColor
        shapeLayer.lineWidth = 1.0
        viewWithBeizer.layer.addSublayer(shapeLayer)
        return viewWithBeizer
        
    }
    
}

结果(蓝线不可见,因为我们在上面添加了红线):

不过,更好的方法是 A) 使用自动布局约束,以及 B) 在自定义 UIView 子类中处理 shapeLayer 逻辑——但这是另一个话题。