二次曲线在不同设备上无法正确呈现

Quadratic curve not rendered correctly on different devices

我正在尝试绘制中间有二次曲线的贝塞尔路径。该曲线在 iPhone 8 和 XS 上运行良好,但在其他设备上没有响应(即未正确呈现)。

下面是 iPhone XS 曲线图(正确)

和iPhone XR(不正确)

我尝试使用视图的约束来获取线的中间值,但不知何故它仍然不起作用

这是我绘制路径的代码:

//self.viewTabBorder is the grey line, which is a uiview with 1 pixel height
override func viewWillAppear(_ animated: Bool) {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: self.viewTabBorder.center.x - self.btnHome.frame.width + 20, y: 0))
        path.addQuadCurve(to: CGPoint(x: self.viewTabBorder.center.x + self.btnHome.frame.size.width - 20, y: 0), controlPoint: CGPoint(x: self.viewTabBorder.center.x, y: self.btnHome.frame.height + 5))
        path.addLine(to: CGPoint(x: self.viewTabBorder.center.x + self.btnHome.frame.size.width - 20, y: 0))

        let line = CAShapeLayer()
        line.path = path.cgPath
        line.strokeColor = UIColor(red: 224, green: 224, blue: 224).cgColor
        line.fillColor = UIColor.white.cgColor
        self.view.layer.addSublayer(line)
        self.viewTabBorder.layer.addSublayer(line)
    }

谁能告诉我我缺少什么?非常感谢您!

一些观察:

  1. 您正在定义子图层到视图的路径。在 viewWillAppear 中执行此过程还为时过早。布局引擎可能没有完成应用约束,将视图放置在它们的最终位置。在 viewDidLayoutSubviews 中定义路径,而不是在 viewWillAppear 中(也不在 viewDidLoad 中,也不在 viewWillLayoutSubviews 中)。

    这还有一个好处,如果您更改应用程序以支持多个方向或进行任何影响视图约束的更改,这 viewDidLayoutSubviews 我们将再次调用,以便正确更新这些子层如所须。如果您使用 viewWillAppear,您的应用将不支持动态更改您的视图(如果您需要的话)。

  2. 话虽如此,请注意 viewDidLayoutSubviews 可以多次调用。例如,您可以在 viewDidLoad 中添加子图层,但在 viewDidLayoutSubviews.

    中更新它们的路径
  3. 这可能不是问题,但我建议您在定义子图层的路径时避免使用 framecenter。请记住,这两个属性是在其 superview 的坐标系中定义的。 我建议您始终使用视图的 bounds(在视图自己的坐标系中定义),而不是它的 frame (在其父视图的坐标系中定义)试图为子图层定义路径时。例如,如果您想要在定义子图层路径时视图的水平中心,请使用 bounds.midX 而不是 center.x

    有时这无关紧要(如果视图在其父视图中 edge-to-edge),但 (a) 它表明对不同坐标系的误解; (b) 如果您曾经添加安全区域或以其他方式调整视图的位置,使用 frame/center 会给您带来麻烦。


一个稍微高级的概念:一旦你解决了眼前的问题,你可能会考虑将子视图的这种配置移动到 UIView subclass(使用它的 layoutSubviews 方法), 甚至可能使它成为 @IBDesignable class 这样你就可以在 Interface Builder 中看到它的呈现。或者,另一种方法是将其包装在容器视图控制器中。但无论哪种方式,这都有助于防止视图控制器“膨胀”。这可能有点超出了这个问题的范围,但在你继续前进的过程中需要考虑一些事情。