viewWillAppear: 和 viewDidAppear: 之间的视图框架变化

2022-01-12 00:00:00 iphone objective-c ios uiscrollview

我在我的应用程序中发现了一个奇怪的行为,其中连接的 IBOutlet 在我的视图控制器中对 viewWillAppear: 的调用之间具有其连接的视图框架viewDidAppear:.这是我的 UIViewController 子类中的相关代码:

I have discovered a strange behavior in my application, where a connected IBOutlet has its connected view's frame between the calls in my view controller to viewWillAppear: and viewDidAppear:. Here is the relevant code in my UIViewController subclass:

-(void)viewWillAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

-(void)viewDidAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

以及生成的日志输出:

MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 0; 0 0); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 44; 320 416); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>

这清楚地表明框架在两次调用之间发生了变化.我想在 viewDidLoad 方法中对视图进行设置,但如果内容在屏幕上之前无法更改,那似乎毫无用处.会发生什么?

Which clearly shows that the frame is changing between the two calls. I wanted to do setup with the view in the viewDidLoad method, but if the content is not available for me to change until it is on the screen, that seems pretty useless. What could be happening?

推荐答案

Autolayout 对我们设计和开发视图 GUI 的方式进行了巨大改变.主要区别之一是 autolayout 不会立即更改我们的视图大小,而是仅在触发时,即在特定时间,但我们可以强制它立即重新计算我们的约束或标记它们作为布局的需要".它的工作方式类似于 -setNeedDisplay.
对我来说最大的挑战是要理解并接受这一点,我们不再需要使用自动调整大小的蒙版,而框架在放置我们的视图时已成为无用的属性.我们不再需要考虑视图位置,但我们应该考虑我们希望如何在彼此相关的空间中看到它们.
当我们想要混合旧的自动调整大小蒙版和自动布局时,就会出现问题.我们应该尽快考虑自动布局的实现,并尽量避免在基于自动布局的视图层次结构中混合旧方法.
拥有一个仅使用自动调整大小掩码的容器视图是可以的,例如视图控制器的主视图,但如果我们不尝试混合使用会更好.
我从未使用过故事板,但很可能它是正确的.使用自动布局,您的视图框架在自动布局引擎开始计算时设置.尝试在视图控制器的 - (void)viewDidLayoutSubviews 方法的 super 之后询问同样的问题.
当自动布局引擎完成计算视图的帧时调用此方法.

Autolayout made a huge change in how we design and develop the GUI of our views. One of the main differences is that autolayout doesn't change our view sizes immediately, but only when is triggered, that means at a specific time, but we can force it to recalculate our constraints immediately or mark them as "in need" of layout. It works like -setNeedDisplay.
The big challenge for me was to understand and accept that, we do not need to use autoresizing masks anymore, and frame has become a useless property in placing our views. We do not need to think about view position anymore, but we should think how we want to see them in a space related to each other.
When we want to mix old autoresizing mask and autolayout is when problems arise. We should think about autolayout implementation really soon and try to avoid to mix the old approach in a view hierarchy based on autolayout.
Is fine to have a container view that uses only autoresizing masks, such as a main view of a view controller, but is better if we do not try to mix.
I never used storyboard, but most proably it is correct. Using Autolayout, frame of your views are set when the autolayout engine starts its calculation. Try to ask the same thing right after super of - (void)viewDidLayoutSubviews method of your view controller.
This method is called when the autolayout engine has finished to calculate your views' frames.

相关文章