【问题标题】:does anybody understand this paradox with swift frames?有人用快速帧理解这个悖论吗?
【发布时间】:2022-01-12 15:49:26
【问题描述】:

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

import UIKit

类视图控制器: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

    

}

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

【问题讨论】:

  • 不是您问题的答案,但属性名称(TopView、MiddleView、BottomView)和函数名称(func Vvp())应以小写字母开头(TopView 应为 topView。 )
  • sorry - bigV 来自课堂,一小时前 VVP 是课堂,我将其更改为 func 显示在这里
  • 只是一个猜测,但这对我来说感觉就像您在 UIView/UIViewController 生命周期中的错误时间点创建这些层/路径。放置一些断点并检查何时这些视图实际上有框架。通常它位于viewWillLayoutSubviewsviewDidLayoutSubviews 中(对于UIViewController,您可能应该在其中工作)。他们都可能会被调用几次,而后者通常更好。
  • 谢谢,好一点,行之间的差异是 10 毫米。问题是为什么?为什么当我将帧传递给 func 时 - 它创建的行低于我直接从具有相同 var 的视图控制器创建的行?这很愚蠢。

标签: swift uikit frame


【解决方案1】:

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

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

根据您的屏幕截图,您正在基于带有 Notch 的 iPhone 型号在 Storyboard 中布置视图...因此,在 viewDidLoad() 中,您的 TopView 具有在 Storyboard 中设置的框架。

这是在 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 逻辑 - 但这是另一个主题。

【讨论】:

  • 谢谢,非常好!
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2012-05-20
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    • 2012-08-22
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多