1

我正在尝试绘制一条中间有二次曲线的贝塞尔路径。该曲线在 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)
    }

谁能告诉我我错过了什么?非常感谢您!

4

1 回答 1

1

几点观察:

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

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

  2. 话虽如此,请注意viewDidLayoutSubviews可以多次调用。因此,例如,您可以在 中添加子层viewDidLoad,但在 中更新它们的路径viewDidLayoutSubviews

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

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


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

于 2019-07-09T05:54:37.670 回答