我正在尝试绘制一条贝塞尔曲线,中间有一个二次曲线。该曲线在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)
}
有人可以告诉我我所缺少的吗?提前非常感谢您!
答案 0 :(得分:1)
一些观察结果:
您正在定义视图的子层的路径。在viewWillAppear
中执行此操作还为时过早。应用约束可能无法完成布局引擎,将视图放置在其最终位置。在viewDidLayoutSubviews
中而不是在viewWillAppear
中(不是viewDidLoad
也不是viewWillLayoutSubviews
)中定义路径。
这还具有以下优点:如果您更改应用程序以支持多种方向或进行任何会影响视图约束的更改,我们将再次调用此viewDidLayoutSubviews
,以便可以根据需要正确更新这些子层。如果您使用viewWillAppear
,则您的应用将不支持对视图的动态更改(您是否需要这样做)。
话虽如此,请注意viewDidLayoutSubviews
可以被多次调用。因此,您可以例如在viewDidLoad
中添加子层,但在viewDidLayoutSubviews
中更新其路径。
在这里这可能不是问题,但我建议您在为子层定义路径时避免使用frame
或center
。请记住,这两个属性是在其 superview的坐标系中定义的。我建议您始终使用视图的bounds
(在视图自身的坐标系中定义),而不要使用其{{ 1}}(在其父视图的坐标系中定义),当尝试为子层定义路径时。而且,例如,在定义子图层的路径时,如果需要视图的水平中心,请使用frame
而不是bounds.midX
。
有时候这无关紧要(如果视图在其超级视图中是从一边到另一边),但是(a)这表明对不同的坐标系有误解; (b)如果您曾经添加安全区域或以其他方式调整视图的位置,则使用center.x
/ frame
会给您带来麻烦。
一个稍微高级的概念:一旦您遇到了直接的问题,您可以考虑将这种子视图配置移到center
子类中(使用其UIView
方法),甚至可能使其成为layoutSubviews
类,因此您可以在Interface Builder中看到它。或者,另一种方法是将其包装在容器视图控制器中。但这两种方式都可以帮助防止视图控制器“膨胀”。这可能超出了此问题的范围,但是在您前进时需要考虑一些问题。