如果在 viewDidLoad 之外启用横幅广告,则旋转后布局不正确

Incorrect layout after rotation if banner ads enabled outside of viewDidLoad

我在使用 iOS 8 应用程序时遇到问题。我的应用程序需要从网络服务器获取信息以确定是否应播放广告。这可能需要一段时间,因此 viewDidLoad 中的代码不会等待它而是调用 setCanDisplayBannerAds:NO。然后稍后,一旦信息进来, setCanDisplayBannerAds:YESviewDidLoad.

之外被调用

我已确定我需要在 viewDidLoad 内调用 setCanDisplayBannerAds:NO,否则 setCanDisplayBannerAds:YES 无法正确调用广告并生成大量内部异常。

问题是一旦在 viewdidLoad 之外启用广告,布局就会混乱。我在下面用两张图片进行了说明。顶部是 "before",底部是 "after",就像点击 显示广告 后一样。

请注意,在 "before" 图像中,Show AdsJust a Label 旋转后都出现在各自的角落。在 "after" 图像中,横向不再正确。它通过 仅一个标签 和横幅广告被截断来保持纵向边界。

我已向 Apple 提交错误报告,并提供了一个示例项目,可在 DropBox 上访问 ID19658866.zip。欢迎下载试用。

如果有人可以提供一些见解,也许可以提供一个解决方案,我不必更改逻辑顺序,即在 viewDidLoad 完成之前不展示广告,将不胜感激。

完全摸不着头脑,但是如果您在广告进入后调用 setNeedsLayout 或 setneedsupdatecontraint(假设您使用的是自动布局,我认为您是)会发生什么情况?此外,请确保在广告视图和其他视图之间正确设置了约束。这些可能不是正确的答案,但我希望它能提供一些关于真实 problem/solution.

的额外见解

把这两行放在viewdidLoad:

[self setCanDisplayBannerAds:YES];
[self setCanDisplayBannerAds:NO];

第一个电话会正确设置广告,第二个电话会立即确保它们不会展示。稍后您可以调用 [self setCanDisplayBannerAds:YES];,它将毫无问题地处理方向更改。

老实说, 可能会起作用,至少对于当前的 SDK 是这样。但是感觉有点奇怪。它并没有真正解释 为什么 它会起作用。

查看 setCanDisplayBannerAds: 的文档,我们看到:

It's important to note that this will modify the view hierarchy of the view controller by inserting a new container view above the view controller's view. The impact is that the view controller's view property will no longer return the originally provided view, it will return the new container. To access the original view, use the originalContentView property.

所以它实际上取代了您的 UIViewController 的 .view 属性。请记住这一点。

当 UIViewController 显示在屏幕上时,它会调整大小以适合整个屏幕(或至少适合它占用的容器)。因此,UIViewController 的 .view 属性 得到 UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidthautoresizing mask,所以它的高度和宽度是灵活的,它可以拉伸以适应容器。

当您在 viewDidLoad 中调用 [self setCanDisplayBannerAds:YES]; 时,您的 UIViewController 的 .view 属性 将被替换为新的 UIView,并且由于它在 viewDidLoad 中,它的 autoresizingMask 得到适当设置。相反,在 viewDidLoad 中调用 [self setCanDisplayBannerAds:NO]; 实际上什么都不做。

在您的示例应用程序中,当您在 viewDidLoad 的 之外调用 [self setCanDisplayBannerAds:YES]; 时,我们可以看到 autoresizingMask 执行 not 实际上设置为拉伸。这就是导致问题的原因:

- (IBAction)TouchUpInside:(id)sender {
    NSLog(@"Touch Up Inside");
    NSLog(@"Original View: %@", self.view);
    [self setCanDisplayBannerAds:YES];
    NSLog(@"New View: %@", self.view);
    NSLog(@"Content View: %@", self.originalContentView);
}

Output: 
2015-02-05 11:32:19.654 ID19658866[12404:3600041] Touch Up Inside
2015-02-05 11:32:19.655 ID19658866[12404:3600041] Original View: <UIView: 0x7f9c42717440; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f9c42717710>>
2015-02-05 11:32:19.666 ID19658866[12404:3600041] New View: <UIView: 0x7f9c42523fb0; frame = (0 0; 375 667); layer = <CALayer: 0x7f9c42524080>>
2015-02-05 11:32:19.666 ID19658866[12404:3600041] Content View: <UIView: 0x7f9c42717440; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f9c42717710>>

这里的关键点在输出的第 3 行,其中 "New View" 而不是 在输出中包含 autoresize = W+H;。我们还确认 self.view 在输出的第 2 行和第 3 行之间被新视图替换。

为了解决这个问题,我们可以确保我们的新 self.view 属性 通过在我们调用 [self setCanDisplayBannerAds:YES]; 之后添加此行来获得所需的 autoresizingMask

self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

它会起作用,我们会知道为什么。

或者我们可以,你知道...通过在 viewDidLoad 中调用 [self setCanDisplayBannerAds:YES]; 来替换我们的 self.view 属性,因此它会自动获得 autoresizingMask 设置正确。

坦率地说,荣益民是所有可用的中最好的。但是,如果这是高级帐户类型和标准帐户类型,那么最好在本地存储一个变量并让用户点击 "restore purchase" 按钮。这样,即使用户处于离线状态,您也可以展示广告(如果它们存储在本地)并且当它们在线时,您可以从广告商那里收取利润。祝你申请成功!