-
layoutSubviews
:您可以将此调用依赖于大小已更改的视图,或者如果该视图已接收到
setNeedsLayout
. 如果视图的位置发生变化,但其大小不变,则系统不会自动调用
布局子视图
在那个视图上。
-
frame didSet
:这适用于使用
autoresizingMask
. 它不适用于使用普通约束布局的视图。相反,自动布局设置视图的
center
和
bounds
. 但是,这些是实现细节,可能在不同版本的uikit中发生更改。我在Xcode10测试版6附带的iOS12.0模拟器上进行了测试。
-
KVon
frame
:这在某些情况下不会起作用,原因与2相同。也,
框架
未记录为符合kvo,因此允许更改uikit
框架
不通知观察员。
-
viewDidLayoutSubviews
:只有当视图是
view
视图控制器的属性,然后仅当
看法
接收
布局子视图
信息(见1)。另外,重要的是要理解,当调用这个函数时,视图控制器的
看法
它的直接的子视图已经布置好了,但更深层的子视图
不
已经布置好了。(见
this answer
为了更全面的解释。)
还要注意,视图
框架
是根据它的一些属性
layer
:层的
position
,
bounds.size
,
anchorPoint
和
transform
. 如果有任何东西直接设置这些层属性,那么上面的方法都不起作用。
因为这些,没有什么特别的
伟大的
视图位置更改时的通知方式。技术上正确的方法可能是使用
CAAction
. 当层检测到
位置
正在更改,它要求其委托(视图本身,视图的层)运行操作。它通过发送
actionForLayer:forKey:
消息。以便您可以覆盖
action(forLayer:forKey:)
在视图中,子类将得到可靠的通知。但是,层请求操作
之前
改变它的
位置
(因此
框架
)它执行动作
之后
改变它的
位置
. 所以你要跳这样的小舞蹈:
override func action(for layer: CALayer, forKey event: String) -> CAAction? {
class MyAction: CAAction {
init(view: MyView, nextAction: CAAction?) {
self.view = view
self.nextAction = nextAction
}
let view: MyView
let nextAction: CAAction?
func run(forKey event: String, object: Any, arguments: [AnyHashable : Any]?) {
// THIS IS WHERE YOU LOOK AT THE NEW FRAME AND ACT ACCORDINGLY.
print("This is the action. Frame now: \(view.frame)")
nextAction?.run(forKey: event, object: object, arguments: arguments)
}
}
let action = super.action(for: layer, forKey: event)
if event == "position" {
return MyAction(view: self, nextAction: action)
} else {
return action
}
}
这个
UIView
实施
层操作:分叉:
正常返回
nil
. 但在动画块内(包括当界面在纵向和横向之间旋转时),它返回(对于某些键)安装
CAAnimation
在层上。所以运行返回的操作很重要
super
如果有的话。