为什么在我移动 UISlider 时调用 viewDidLayoutSubviews()?
Why is viewDidLayoutSubviews() being called when I move UISliders?
当我移动 UISlider
时,我的 ViewController 的 viewDidLayoutSubviews()
方法被重复调用。 (我需要它被调用一次,这样我才能计算出子视图的大小——viewDidLoad()
在这个过程中太早了——但是当我拖动 UISlider
时它被无限调用。)
如有任何想法,我们将不胜感激!
既然你提到viewDidLoad
太早了,你能在viewWillAppear:
或viewDidAppear:
中计算吗?
viewDidLayoutSubviews
由于多种原因被多次调用。您不能依赖或更改此调用的频率(例如,当状态栏更改高度时调用它)。
A UISlider
使用拇指和轨道部分的子视图绘制自己。这是一个简单的测试应用程序的视图层次结构:
<UIWindow: 0x7d26cf90; frame = (0 0; 320 480); autoresize = W+H; gestureRecognizers = <NSArray: 0x7d2609a0>; layer = <UIWindowLayer: 0x7d25f0c0>>
| <UIView: 0x7d27d530; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x7d27cec0>>
| | <UISlider: 0x7d27d700; frame = (14 225; 292 31); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7d27d960>; value: 0.513699>
| | | <UIView: 0x7b755a50; frame = (150 15; 140 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7b7559d0>>
| | | | <UIImageView: 0x7b7551d0; frame = (-148 0; 288 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7b755410>>
| | | <UIImageView: 0x7b755640; frame = (2 15; 148 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7b755720>>
| | | <UIImageView: 0x7d5c3450; frame = (134 0; 31 31); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7d5c4750>>
| | | | <UIImageView: 0x7d5c44a0; frame = (-13 -6.5; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7d5c6c20>>
| | <_UILayoutGuide: 0x7d27daa0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7d27ccf0>>
| | <_UILayoutGuide: 0x7d27e020; frame = (0 480; 0 0); hidden = YES; layer = <CALayer: 0x7d27e0f0>>
请注意,UISlider
共有五个后代视图。这是您不应依赖的实施细节,但有助于了解正在发生的事情。
当滑块需要更改其值时,它会将新值存储在实例变量中并设置自己的 needsLayout
标志。最终,运行 循环到达布局阶段,视图层次结构布局被更新,从 window 开始并沿着层次结构向下移动。当它到达滑块时,滑块根据其值和其他实例变量更新其子视图的帧。
如果您需要知道子视图的大小,您可能需要自己调用 layoutIfNeeded
,然后立即获取子视图的大小,以便在您的控制下进行布局。
当我移动 UISlider
时,我的 ViewController 的 viewDidLayoutSubviews()
方法被重复调用。 (我需要它被调用一次,这样我才能计算出子视图的大小——viewDidLoad()
在这个过程中太早了——但是当我拖动 UISlider
时它被无限调用。)
如有任何想法,我们将不胜感激!
既然你提到viewDidLoad
太早了,你能在viewWillAppear:
或viewDidAppear:
中计算吗?
viewDidLayoutSubviews
由于多种原因被多次调用。您不能依赖或更改此调用的频率(例如,当状态栏更改高度时调用它)。
A UISlider
使用拇指和轨道部分的子视图绘制自己。这是一个简单的测试应用程序的视图层次结构:
<UIWindow: 0x7d26cf90; frame = (0 0; 320 480); autoresize = W+H; gestureRecognizers = <NSArray: 0x7d2609a0>; layer = <UIWindowLayer: 0x7d25f0c0>>
| <UIView: 0x7d27d530; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x7d27cec0>>
| | <UISlider: 0x7d27d700; frame = (14 225; 292 31); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7d27d960>; value: 0.513699>
| | | <UIView: 0x7b755a50; frame = (150 15; 140 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7b7559d0>>
| | | | <UIImageView: 0x7b7551d0; frame = (-148 0; 288 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7b755410>>
| | | <UIImageView: 0x7b755640; frame = (2 15; 148 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7b755720>>
| | | <UIImageView: 0x7d5c3450; frame = (134 0; 31 31); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7d5c4750>>
| | | | <UIImageView: 0x7d5c44a0; frame = (-13 -6.5; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7d5c6c20>>
| | <_UILayoutGuide: 0x7d27daa0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7d27ccf0>>
| | <_UILayoutGuide: 0x7d27e020; frame = (0 480; 0 0); hidden = YES; layer = <CALayer: 0x7d27e0f0>>
请注意,UISlider
共有五个后代视图。这是您不应依赖的实施细节,但有助于了解正在发生的事情。
当滑块需要更改其值时,它会将新值存储在实例变量中并设置自己的 needsLayout
标志。最终,运行 循环到达布局阶段,视图层次结构布局被更新,从 window 开始并沿着层次结构向下移动。当它到达滑块时,滑块根据其值和其他实例变量更新其子视图的帧。
如果您需要知道子视图的大小,您可能需要自己调用 layoutIfNeeded
,然后立即获取子视图的大小,以便在您的控制下进行布局。