gpt4 book ai didi

ios - subview 何时完全、正确地布局?

转载 作者:搜寻专家 更新时间:2023-11-01 05:46:52 27 4
gpt4 key购买 nike

我正在尝试以编程方式绘制一个圆形进度 View 并将其置于 subview circleView 的中心,我已经在界面构建器中设置/限制了它。但是,我不确定何时可以访问 circleView 的最终大小和中心(我正在使用自动布局),我最终需要绘制圆圈。这是涉及的代码:

@IBOutlet weak var circleView: UIView!

let circleShapeLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()

override func viewDidLoad() {
super.viewDidLoad()
// createCircle()
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

print(circleView.frame.size.width)
createCircle()
}

func createCircle() {

// Draw/modify circle

let center = circleView.center

// Where I need to use circleView's width/center
let circularPath = UIBezierPath(arcCenter: center, radius: circleView.frame.size.width, startAngle: -CGFloat.pi/2, endAngle: 2 * CGFloat.pi, clockwise: true)

trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = UIColor.lightGray.cgColor
trackLayer.lineWidth = 10
trackLayer.fillColor = UIColor.clear.cgColor

circleView.layer.addSublayer(trackLayer)

circleShapeLayer.path = circularPath.cgPath
circleShapeLayer.strokeColor = Colors.tintColor.cgColor
circleShapeLayer.lineWidth = 10
circleShapeLayer.fillColor = UIColor.clear.cgColor
circleShapeLayer.lineCap = kCALineCapRound
// circleShapeLayer.strokeEnd = 0

circleView.layer.addSublayer(circleShapeLayer)

}

这会打印两次 circleView 的宽度,只有在第二次运行 viewDidLayoutSubviews() 时才正确:

207.0
187.5 // Correct (width of entire view is 375)

但是,圆两次都沿着相同的路径绘制错误,这让我感到困惑,因为宽度如上所示发生了变化。也许我在以错误的方式思考这个问题?

我宁愿不画圆圈两次,并希望有一种方法可以在 viewDidLoad() 中运行 createCircle(),但目前这只是给我同样的结果。非常感谢任何帮助。

最佳答案

@rmaddy 的评论是正确的:处理此问题的最佳方法是使用自定义 View 来管理 trackLayercircleShapeLayer。覆盖自定义 View 的 layoutSubviews 以设置图层的框架和/或路径。

也就是说,我将回答您提出的问题“ subview 何时完全、正确地布局?”

考虑这个 View 层次结构:

A
|
+--- B
| |
| +--- C
| |
| +--- D
|
+--- E
|
+--- F
|
+--- G

在run loop的布局阶段,Core Animation以深度优先的顺序遍历图层层次结构,寻找需要布局的图层。所以Core Animation首先访问A的层,然后是B的层,然后是C的层,然后是D的层,然后是E的层,然后是F的层,然后是G的层。

如果一个图层需要布局(它的needsLayout 属性为真),Core Animation 会发送layoutSublayers 给图层。默认情况下,图层通过将 layoutSublayersOfLayer: 发送到其委托(delegate)来处理此问题。通常委托(delegate)是拥有层的 UIView

默认情况下,UIView 处理 layoutSublayersOfLayer: 通过(除其他事项外)发送三个消息:

  1. UIViewviewWillLayoutSubviews 发送到它的 View Controller ,如果 View 由 View Controller 所有的话。
  2. UIView 发送自己的 layoutSubviews
  3. UIViewviewDidLayoutSubviews 发送到它的 View Controller ,如果 View 由 View Controller 所有的话。

-[UIView layoutSubviews] 的默认实现中, View 根据自动布局约束设置其每个直接 subview 的框架。

请注意,在 layoutSubviews 中, View 仅设置其直接 subview 的框架。因此,例如,A 仅设置 B 和 E 的框架。它设置 C、D、F 和 G 的框架。

所以让我们假设 A 是 View Controller 的 View ,但其他 View 都不属于 View Controller 。

当 A 处理 layoutSubviews 时,它设置 B 和 E 的框架。然后它发送 viewDidLayoutSubviews 到它的 View Controller 。 C、D、F 和 G 的帧此时更新。 View Controller 不能假定 C、D、F 和 G 在其 viewDidLayoutSubviews 中具有正确的框架。

有两个好地方可以放置在 C 的框架肯定更新时运行的代码:

  1. 覆盖 B 的 layoutSubviews。由于 B 是 C 的直接父 View ,因此可以确定在 B 的 layoutSubviews 调用 super.layoutSubviews() 之后,C 的框架已经更新。

    <
  2. 让一个 View Controller 负责 B。也就是说,让 B 成为某个 View Controller 的 View 。然后,在拥有 B 的 View Controller 中覆盖 viewDidLayoutSubviews

如果您只需要知道 C 的大小何时确定更新,您有第三种选择:

  1. 覆盖 C 的 layoutSubviews。如果 C 改变大小,这将被调用。如果 C 改变位置但保持相同大小,则不一定会调用它。

关于ios - subview 何时完全、正确地布局?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51254261/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com