【问题标题】:View added in applicationDidEnterBackground not visible until app returns from background在应用程序从后台返回之前,在 applicationDidEnterBackground 中添加的视图不可见
【发布时间】:2015-06-05 12:46:41
【问题描述】:

我在 applicationDidEnterBackground 的应用程序主窗口中添加了一个 imageView:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
        UIImageView *splash = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"splashimage.png"]];
        splash.frame = self.window.bounds;
        [self.window addSubview:splash];
}

我希望当我通过按下设备的主页按钮将应用程序置于后台,然后通过双击主页按钮查看任务管理器时,我会看到 splashimage.png 显示。但似乎应用程序进入后台时截取的屏幕截图不包括此叠加图像视图。我以为会的,因为我添加了没有动画的 imageView。

为什么会发生这种情况?

更新:即使我在 applicationDidEnterBackground 中隐藏我的窗口,在应用程序进入后台状态后,我仍然可以在任务管理器中看到未隐藏的完整窗口。应用程序从后台返回后,当我按下主页按钮时,该窗口才会隐藏。

- (void)applicationDidEnterBackground:(UIApplication *)application
{
        //this does not work either!
        self.window.hidden = YES;
}

更新:顺便说一下,我确实理解 applicationDidEnterBackground 有 5 秒的时间来完成。我现在只用这个测试

self.window.hidden = YES;

在applicationDidEnterBackground中和applicationWillResignActive中什么都没有,并且当应用进入后台时窗口仍然没有隐藏;只有当它返回到前台时。所以这告诉我,在我的应用程序的某个地方,一定有其他东西不允许在 applicationDidEnterBackground 中发生这种情况。顺便说一句,如果我移动了

self.window.hidden = YES;

对于 applicationWillResignActive,当应用程序进入后台时窗口被隐藏。但我试图弄清楚什么会阻止应用程序完成 applicationDidEnterBackground 中的这个单一、简单、非动画的任务。任何想法表示赞赏。

更新:此特定问题与使用 BannerViewController (iAd) 有关。我在 UITabBarController 中使用它。尚不确定究竟是什么问题,或者它是否也与它在 UITabBarController 中的使用有关。

更新:我认为该问题与 UITabBarController 无关,但通常与 BannerViewController (iAd) 有关。现在明白为什么...

更新:BannerViewController.m 中的这一行导致了问题:

[self.view addSubview:bannerView]

在这个方法中:

- (void)viewDidLayoutSubviews
{
    CGRect contentFrame = self.view.bounds, bannerFrame = CGRectZero;
    ADBannerView *bannerView = [BannerViewManager sharedInstance].bannerView;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
    NSString *contentSizeIdentifier;
    // If configured to support iOS <6.0, then we need to set the currentContentSizeIdentifier in order to resize the banner properly.
    // This continues to work on iOS 6.0, so we won't need to do anything further to resize the banner.
    if (contentFrame.size.width < contentFrame.size.height) {
        contentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
    } else {
        contentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
    }
    bannerFrame.size = [ADBannerView sizeFromBannerContentSizeIdentifier:contentSizeIdentifier];
#else
    // If configured to support iOS >= 6.0 only, then we want to avoid currentContentSizeIdentifier as it is deprecated.
    // Fortunately all we need to do is ask the banner for a size that fits into the layout area we are using.
    // At this point in this method contentFrame=self.view.bounds, so we'll use that size for the layout.
    bannerFrame.size = [_bannerView sizeThatFits:contentFrame.size];
#endif

    if (bannerView.bannerLoaded) {
        contentFrame.size.height -= bannerFrame.size.height;
        bannerFrame.origin.y = contentFrame.size.height;
    } else {
        bannerFrame.origin.y = contentFrame.size.height;
    }
    _contentController.view.frame = contentFrame;
    // We only want to modify the banner view itself if this view controller is actually visible to the user.
    // This prevents us from modifying it while it is being displayed elsewhere.
    if (self.isViewLoaded && (self.view.window != nil)) {
        [self.view addSubview:bannerView];
        bannerView.frame = bannerFrame;
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0
        bannerView.currentContentSizeIdentifier = contentSizeIdentifier;
#endif
    }
}

不完全确定为什么或什么,如果我仍然想使用 BannerViewController,是否可以做任何事情来解决它。

更新:从下面接受的答案,这是为我解决这个问题的方法(bannerVC 是对 BannerViewController 的引用)。

- (void)applicationWillResignActive:(UIApplication *)application {

    [bannerVC.view snapshotViewAfterScreenUpdates:YES];
}

更新:我意识到这段代码确实应该在 applicationDidEnterBackground 中。但是,使用 AdBannerView 似乎无法及时停止动画,以便发生这种情况。所以现在,据我了解,applicationWillResignActive 是剩下的,但它给用户留下了“低于”的体验。我将不胜感激有关如何停止 AdBannerView 动画的任何建议,以便快照可以显示在 applicationDidEnterBackground 中,而不仅仅是从后台返回时。

更新: 复制问题:

  1. 下载iAdSuite
  2. 打开 TabbedBanner 示例。
  3. 将以下代码添加到 AppDelegate:
  4. 运行应用程序。 (框架因为尚未更新而混乱,但此示例仍会显示问题)
  5. 点按一次主页按钮可将应用置于后台。
  6. 双击主页按钮可在任务管理器中查看该应用。

如果您将 applicationWillResignActive 中的代码保留为注释,而 applicationDidEnterBackground 中的代码未注释,您将不会在任务管理器中看到蓝色的闪屏。但是,如果您在 applicationDidEnterBackground 中注释了代码并取消注释 applicationWillResignActive 中的代码,您应该会在任务管理器中看到蓝色的闪屏。然而,这是不可取的。问题是如何在 applicationDidEnterBackground 方法中显示启动画面。

- (void)applicationWillResignActive:(UIApplication *)application {

    //works - but undesirable
    //[self addDummyView];
    //[_tabBarController.view snapshotViewAfterScreenUpdates:YES];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {

    //does not work - needs to work to show dummyview only when application actually goes into the background
    [self addDummyView];
    [_tabBarController.view snapshotViewAfterScreenUpdates:YES];
}

- (void)addDummyView {

    UIView *topView = _tabBarController.view;
    UIView *colorView = [[UIView alloc] initWithFrame:topView.frame];
    [colorView setBackgroundColor:[UIColor blueColor]];
    [topView addSubview:colorView];
    [topView bringSubviewToFront:colorView];
}

【问题讨论】:

  • 但我的回答被贬低了:(

标签: ios user-interface window lifecycle multitasking


【解决方案1】:

当 applicationDidEnterBackground 方法返回时,应用程序当前视图的快照被用于多任务视图。您没有看到更新的原因是因为快照是在绘图周期之前拍摄的。即使您调用 setNeedsDisplay,快照仍然是之前拍摄的。

要等到视图更新(在添加子视图之后)调用:

[self.view snapshotViewAfterScreenUpdates:YES];

值为YES。这会强制您的更改首先呈现。您可以在此处的 Apple 文档中阅读有关处理此类内容的更多信息:https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html#//apple_ref/doc/uid/TP40007072-CH8-SW27

【讨论】:

  • 我在哪里调用它 - 在 applicationDidEnterBackground 中?从查看文档看来,我需要从 ViewController 调用它,但我不确定那会是哪一个,或者我会在哪里添加此代码。我肯定会尝试看看这是否可以帮助我解决我的问题,因为我已经确定了它的来源。
  • 我认为您可以从应用程序委托中使用它:[[[UIApplication sharedApplication].windows firstObject] snapshotViewAfterScreenUpdates:YES]; .否则监听来自视图控制器的通知。
  • 我看到我可以从这个方法获得一个视图(它返回一个视图),但我不确定如何用这个视图替换应用程序进入后台时使用的快照视图。不确定这是我问题的答案,但我会继续检查它,直到我可以确定排除它为止。
  • 这方面的文档是……缺少。
  • 我明白了!谢谢你。使用 applicationWillResignActive 中的代码,并为 bannerViewController 的视图调用 snapshotViewAfterScreenUpdates:YES。 [bannerVC.view snapshotViewAfterScreenUpdates:YES];
【解决方案2】:

您可以在这里得到答案:Show splash screen when application enters background

将您的代码保存在 applicationWillResignActive 中。

【讨论】:

  • 我想我已经提到我已经可以在 applicationWillResignActive 中完成此任务,并且无需 NSRunLoop hack。这提供了糟糕的用户体验。
  • 是的,我认为这个链接可以帮助你解决你的问题,所以建议,如果它没有帮助,请忽略它。我的强烈只是为了帮助你。谢谢
【解决方案3】:

您的代码很好。您应该知道双击主页按钮时不会调用applicationDidEnterBackground。当您切换到另一个应用程序或转到跳板时会调用它。

因此,您应该只按一次主页按钮,然后双击它,您的应用的屏幕截图应该具有图像视图。我在一个测试项目中复制了你的用例,它对我有用。

如果还是不行,你应该看看 image view 的 image 是不是 nil。哦,请不要隐藏应用程序窗口。

【讨论】:

  • 感谢您的评论。但是我上面说过,我首先“按下设备的主页按钮,然后通过双击主页按钮查看任务管理器”将应用程序置于后台。另外我只是隐藏应用程序窗口进行测试。我永远不会在应用程序中真正做到这一点。还有什么想法吗?
  • 尝试在 `[self.window addSubview:splash]` 上设置断点并测试 imageView 图像是否为空
  • 不是零。而且,正如我还提到的,我什至无法在此方法中成功隐藏应用程序窗口。所以我认为问题一定出在应用程序的其他地方。也许与我使用故事板的事实有关?也许与记忆有关?
  • 在测试项目中我也在使用故事板,所以这不是问题。尝试在 viewDidEnterBackground 中设置断点并一步一步地查看 imageView 是否被正确添加(在前面而不是在后面)。另外,为了调试,将你的图像视图的背景设置为红色,看看你是否看到任何新的东西。
  • 我已经检查了与视图相关的所有内容,一切正常。在这一点上,我关注的是我什至无法在 applicationDidEnterBackground 方法中将窗口设置为隐藏。这表明我的问题出在实际方法之外。
猜你喜欢
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2012-01-14
相关资源
最近更新 更多