在 iOS 单视图应用程序中,self.view.bounds 最早设置正确的时间是啥时候?

Posted

技术标签:

【中文标题】在 iOS 单视图应用程序中,self.view.bounds 最早设置正确的时间是啥时候?【英文标题】:On an iOS single view app, when is the earliest time that self.view.bounds is set correctly?在 iOS 单视图应用程序中,self.view.bounds 最早设置正确的时间是什么时候? 【发布时间】:2012-08-25 03:26:04 【问题描述】:

我正在尝试添加一个覆盖整个屏幕的 UITableView 对象,通过

  UITableView *tabelView = [[UITableView alloc] initWithFrame:self.view.bounds];
  [self.view addSubview:tabelView];

但我意识到即使将物理 iPad 2 旋转到横向模式,self.view.boundsviewDidLoadviewWillAppear 中也是0, 0, 768, 1004。只有viewDidAppear终于0, 0, 1024, 748

self.view.bounds 正确设置为0, 0, 1024, 748 的最早时间是什么时候?如果viewDidAppear是那个,那么我必须在那里创建UITableView,如果“启动图像”是静态横向空白表,那么当调用viewDidAppear时屏幕会闪烁白屏,然后表格被添加并被看到,所以看到一闪而过的白屏。

那么最早将self.view.bounds 正确设置为0, 0, 1024, 748 的时间是什么时候?似乎需要稍早于viewDidAppear,以便绘制空白表格(带有灰色线条),并显示它并无缝显示以覆盖Launch图像。如果表格是在viewDidLoadviewWillAppear 中使用self.view.bounds 创建的,则表格最终为768 磅宽,适用于纵向模式。

更新:我只是尝试添加 Launch 图像,但由于某种原因,即使在 viewDidAppear 中添加了 UITableView,“白屏闪烁”也没有发生……我没有不知道为什么,但是之前如果我使用CALayer和位图来显示内容,并且没有使用任何视图或drawRect,那么就会出现flash...顺便说一句,我发现的最早的是@987654345 @,然后是viewDidLayoutSubviews,两者都发生在viewDidAppear之前,并且都将self.view.bounds显示为0, 0, 1024, 748

更新 2:如果视图制作复杂且耗时怎么办?为了进行测试,我在tableView:cellForRowAtIndexPath 中添加了一个usleep(100000);,以使每个单元格休眠0.1 秒,并且确实发生了“闪光”……但是单元格和表格应该重量轻且制作速度快,但是如果有怎么办制作其他类型的视图是否更耗时?如果我将UITableView创建移动到viewWillLayoutSubviews,那么显示东西还是很慢,但至少没有“闪光”。但是,稍后当我旋转设备时,它实际上再次调用viewWillLayoutSubviews 并将另一个表添加到主视图(具有正确的屏幕尺寸),因此viewWillLayoutSubviews 将需要首先删除任何旧表视图(如果有),或者只需调整旧的大小,不要添加新的。

【问题讨论】:

虽然 self.view.bounds 稍后会更新,但如果您使用 [UIApplication sharedApplication].statusBarOrientation 获取界面方向,您可以在等待设置边界之前决定如何调整表格大小。 @Luke 如果这行得通,这可能有点小题大做,因为如果未来的 ios 设备问世,它不是 iPhone 或 iPad 分辨率,我们需要依靠@ 987654356@? Apple 往往对这些事情很友好,但是虽然我理解你在说什么,但无论如何你都可以这样做(因为你想在视图出现之前绘制表格)然后比较您使用最终 self.view.bounds 生成的框架,然后根据需要进行调整。 @Luke 请查看问题中的更新 UIViewController returns invalid frame? 的可能重复项 【参考方案1】:

避免flash最简单的方法是在viewDidLoad中创建table view,并正确设置table view的autoresizing mask,让系统自动让table view填满它的superview:

- (void)viewDidLoad 
    [super viewDidLoad];
    UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
    tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:tableView];

否则,您可以看到最终视图边界的最早时间是在视图控制器的viewWillLayoutSubviews 方法中。您将在viewDidLoad 中添加一次表格视图,然后在viewWillLayoutSubviews 或之后调用的方法中调整其框架。有关详细信息,请参阅我对 UIViewController returns invalid frame? 的回复。

【讨论】:

实际上,它确实有效 - 即使我在单元格数据源提供程序中添加 sleep(1) 也没有闪存,所以即使表格出来很慢(比如,5 或10 秒),没有闪烁,这是一个有趣的概念:我们首先将视图设置为“不正确”的大小,然后让“调整大小”处理它,然后再将其显示在屏幕上 还有viewWillResizeSubviews 吗?我用谷歌搜索并搜索了您答案中的链接,但没有看到这样的调整大小消息? 没有viewWillResizeSubviews 消息。视图仅在执行自动布局时调整其子视图的大小,然后您会立即收到viewWillLayoutSubviews 因为您在回答中提到了viewWillResizeSubviews...它属于哪里?【参考方案2】:

我试图解决一个类似的问题 - 我想根据在 Interface Builder 中添加的 UIView 的大小以编程方式加载一些 UI 元素。

viewDidLoadviewWillAppear 内部,UIView 仍未设置其框架/边界。将我的代码放在 viewDidAppear 中是可行的,但这意味着 UI 会随着更新而“闪烁”,而不是在将 UIViewController 推送到导航堆栈时显示为已经加载。

我发现覆盖 viewDidLayoutSubviews 解决了这个问题 - 那时,视图有它的边界和框架集 - 我可以在 viewDidAppear 之前添加相对于它的大小的我自己的子视图。

最终结果是 UI 在出现之前就已正确加载,因此不会为用户“闪现”。

【讨论】:

以上是关于在 iOS 单视图应用程序中,self.view.bounds 最早设置正确的时间是啥时候?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ios7 中将 UIView 对象添加到 self.view.window?

添加滚动视图时,所有视图都显示在导航栏后面的self.view顶部

iOS:从顶视图到底视图拦截点击手势事件

iOS - self.view.frame.size.width 为 0.00000

iOS:如何检测视图周围的子视图位置

iOS 视图在不同View之间的切换(对于convertRect:函数的一些理解)