Sid*_*ney 1 uikit uiview ios swift
我正在尝试以编程方式绘制圆形进度视图并将其置于子视图中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)
}
Run Code Online (Sandbox Code Playgroud)
这会打印circleView
两次的宽度,并且只在第二次运行时viewDidLayoutSubviews()
它才真正正确:
207.0
187.5 // Correct (width of entire view is 375)
Run Code Online (Sandbox Code Playgroud)
但是,圆圈在两次都沿着相同的精确路径不正确地绘制,这让我感到困惑,因为宽度如上所示变化.也许我正在考虑这个错误的方法?
我宁愿不画圆两次,希望会有一种方式来运行createCircle()
内viewDidLoad()
代替,但目前这只是给了我同样的结果.任何帮助将非常感谢.
rob*_*off 13
@ rmaddy的评论是正确的:处理此问题的最佳方法是使用自定义视图来管理trackLayer
和circleShapeLayer
.覆盖自定义视图layoutSubviews
以设置图层的框架和/或路径.
也就是说,我会回答你所说的"什么时候子视图完整,正确布局?"
考虑此视图层次结构:
A
|
+--- B
| |
| +--- C
| |
| +--- D
|
+--- E
|
+--- F
|
+--- G
Run Code Online (Sandbox Code Playgroud)
在运行循环的布局阶段,Core Animation以深度优先的顺序遍历层次结构,查找需要布局的图层.因此,核心动画首先访问A层,然后是B层,然后是C层,然后是D层,然后是E层,然后是F层,然后是G层.
如果图层需要布局(其needsLayout
属性为true),则Core Animation将发送layoutSublayers
到图层.默认情况下,图层通过发送layoutSublayersOfLayer:
给其委托来处理此问题.通常委托是UIView
拥有该层的代理.
默认情况下,通过(以及其他)发送三个消息的UIView
句柄layoutSublayersOfLayer:
:
UIView
发送viewWillLayoutSubviews
,如果视图是由视图控制器所拥有的其视图控制器.UIView
将自身发送layoutSubviews
.UIView
发送viewDidLayoutSubviews
,如果视图是由视图控制器所拥有的其视图控制器.在默认实现中-[UIView layoutSubviews]
,视图根据自动布局约束设置每个直接子视图的框架.
请注意,在layoutSubviews
视图中,视图仅设置其直接子视图的帧.因此,例如,A仅设置B和E的帧它不设置C,d,F和G的各帧
因此,假设A是视图控制器的视图,但视图控制器不拥有其他视图.
当A处理时layoutSubviews
,它设置B和E的帧.然后它发送viewDidLayoutSubviews
到它的视图控制器.C,d,F和G的帧已经没有在这一点上被更新.视图控制器不能假设C,D,F和G在其中具有正确的帧viewDidLayoutSubviews
.
当C的帧已经明确更新时,有两个好的地方可以运行代码:
覆盖B的layoutSubviews
.由于B是C的直接超级视图,因此可以确定在B的layoutSubviews
调用之后super.layoutSubviews()
,C的帧已经更新.
放置一个视图控制器来管理B.也就是说,使B成为某个视图控制器的视图.然后,viewDidLayoutSubviews
在拥有B的视图控制器中覆盖.
如果您只需要知道C的大小何时已经更新,那么您有第三种选择:
layoutSubviews
.如果C
更改大小,将调用此方法.如果C改变位置但保持相同的大小,则不一定会调用它. 归档时间: |
|
查看次数: |
518 次 |
最近记录: |