iOS 在进入后台时拍摄视图快照的确切时间? [英] The exact moment iOS takes the view snapshot when entering background?

查看:23
本文介绍了iOS 在进入后台时拍摄视图快照的确切时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在按下退出按钮将我的 iPhone 应用程序置于后台,然后通过点击主屏幕上的启动图标重新启动时遇到问题:应用程序的视图确实像我希望的那样返回到其初始状态,但在此之前它会在屏幕上短暂闪烁早期的错误视图状态.

I have a problem when putting my iPhone app to background by pushing the exit button, and then relaunching by tapping the launch icon on the home screen: the app's view does return to its initial state like I want it to, but before that it flashes the earlier, wrong view state onscreen briefly.

背景

我的主视图基本上由一系列相互关联的 UIAnimateWithDuration 调用组成.每当发生任何中断时,我想要的行为是将动画重置为其初始状态(除非动画全部完成并且应用程序已进入静态最终阶段),并在应用程序返回活动和可见状态时从那里重新开始.

My main view consists basically of a sequence of interlinked UIAnimateWithDuration calls. The behavior I want whenever any interruption occurs, is to reset the animation to its initial state (unless the animations have all finished and the app has entered the static final phase), and start over from there whenever the app returns to active and visible state.

在学习了该主题后,我了解到我需要两种类型的中断处理代码来提供良好的用户体验:即时"和流畅".我有方法 resetAnimation 可以立即将视图属性重置为初始状态,方法 pauseAnimation 可以快速动画到相同状态,并在视图顶部显示暂停"淡入淡出的附加标签.

After studying the subject I learned I need two types of interruption handling code to provide good ux: "instant" and "smooth". I have the method resetAnimation that resets the view properties to the initial state instantly, and the method pauseAnimation that animates quickly to the same state, with an additional label stating "paused" fading in on the top of the view.

双击退出按钮

原因是双击退出按钮"用例,它实际上并没有隐藏您的视图或将您置于后台状态,它只是向上滚动一点以在底部显示多任务菜单.因此,在这种情况下立即重置视图状态看起来非常难看.动画过渡并告诉用户您已暂停似乎是一个更好的主意.

The reason for this is the "double clicking exit button" use case, that actually does not hide your view or put you in the background state, it just scrolls up a bit to show the multitasking menu at the bottom. So, resetting the view state instantly in this case just looked very ugly. The animated transition and telling the user you're paused seemed like a better idea.

通过在我的 App Delegate 中实现 applicationWillResignActive 委托方法并从那里调用 pauseAnimation,此案例运行良好且顺利.我通过实现 applicationDidBecomeActive 委托方法并从那里调用我的 resumeAnimation 方法来处理从该多任务菜单返回的问题,该方法会淡出暂停"标签(如果存在),并从初始状态开始我的动画序列.

This case works nice and smootly by implementing the applicationWillResignActive delegate method in my App Delegate and calling pauseAnimation from there. I handle returning from that multitasking menu by implementing the applicationDidBecomeActive delegate method and calling from there my resumeAnimation method, that fades out the "paused" label if its there, and starts my animation sequence from the initial state.

这一切都很好,没有任何地方闪烁.

This all works fine, no flickering anywhere.

参观另一面

我的应用基于 Xcode实用程序"模板构建,因此它有一个翻转视图来显示信息/设置.我通过在我的主视图控制器中实现这两个委托方法来处理访问反面并返回主视图:

My app's built over the Xcode "utility" template, so it has a flipside view to show info/settings. I handle visiting the flipside and returning back to the main view by implementing these two delegate methods in my main view controller:

  • (void)viewDidDisappear:(BOOL)动画

  • (void)viewDidDisappear:(BOOL)animated

(void)viewDidAppear:(BOOL)动画

(void)viewDidAppear:(BOOL)animated

我在 viewDidDisappear 方法中调用了我的 resetAnimation,在 viewDidAppear 中调用了 resumeAnimation.这一切都很好,主视图是从过渡开始到可见状态的初始状态 - 不会意外闪烁任何错误的动画状态.但是:

I call my resetAnimation in the viewDidDisappear method and resumeAnimation in viewDidAppear. This all works fine, the main view is its initial state from the very beginning of the transition to visible state - no unexpected flashing of wrong animation states of anything. But:

按下退出按钮并从我的应用图标重新启动(错误部分!)

这就是麻烦的开始.当我按下退出按钮一次并且我的应用程序开始转换到后台时,会发生两件事.首先,applicationWillResignActive 也在这里被调用,所以我的 pauseAnimation 方法也启动了.它不需要,因为这里的过渡不需要是平滑的——视图只是静止的,然后缩小"以显示主屏幕——但是你能做什么呢?好吧,如果我可以在系统拍摄视图快照的确切时刻之前调用 resetAnimation 也不会造成任何伤害.

This is where the trouble starts. When I push exit button once and my app begins its transition to background, two things happen. First, applicationWillResignActive gets called here too, so my pauseAnimation method launches also. It wouldn't need to, since the transition doesn't need to be smooth here – the view just goes static, and "zooms out" to reveal the home screen – but what can you do? Well, it wouldn't do any harm either if I just could call resetAnimation before the exact moment that the system takes the snapshot of the view.

无论如何,其次,App Delegate 中的 applicationDidEnterBackground 被调用.我试图从那里调用resetAnimation,以便在应用程序返回时视图处于正确状态,但这似乎不起作用.似乎快照"已经拍摄,因此,当我点击我的应用程序启动图标并重新启动时,错误的视图状态会在正确的初始状态显示之前在屏幕上短暂闪烁.之后,它工作正常,动画按预期运行,但无论我尝试什么,重新启动时的丑陋闪烁都不会消失.

Anyways, secondly, applicationDidEnterBackground in the App Delegate gets called. I tried to call resetAnimation from there so that the view would be in the right state when the app returns, but this doesn't seem to work. It seems the "snapshot" has been taken already and so, when I tap my app launch icon and relauch, the wrong view state does flash briefly on the screen before the correct, initial state shows. After that, it works fine, the animations go about like they're supposed to, but that ugly flicker at that relaunch moment won't go away, no matter what I try.

从根本上说,我所追求的是,​​系统拍摄此快照的确切时间是什么时候?因此,什么是正确的委托方法或通知处理程序来准备我的观点以拍摄纪念品照片"?

PS.然后是 default.png,它似乎不仅在首次启动时显示,而且在处理器遇到困难或返回应用程序因其他原因短暂延迟时也会显示.这有点难看,尤其是当您返回到与默认视图完全不同的反面视图时.但这是一个如此核心的 iOS 功能,我猜我什至不应该试图弄清楚或控制它:)

PS. Then there's the default.png, which doesn't seem to only show at first launch, but also whenever the processor's having a hard time or returning to the app is delayed briefly for some other reason. It's a bit ugly, especially if you're returning to your flipside view that looks totally different from your default view. But this is such a core iOS feature, I'm guessing I shouldn't even try to figure out or control that one :)

由于人们要求提供实际代码,并且在提出这个问题后我的应用程序已经发布,所以我会在这里发布一些.(该应用名为 Sweetest Kid,如果您想了解它的实际工作原理,请访问:http://itunes.apple.com/app/sweetest-kid/id476637106?mt=8 )

since people were asking for actual code, and my app has already been released after asking this question, I'll post some here. ( The app's called Sweetest Kid, and if you want to see how it actually works, it's here: http://itunes.apple.com/app/sweetest-kid/id476637106?mt=8 )

这是我的 pauseAnimation 方法 - resetAnimation 几乎相同,只是它的动画调用的持续时间和延迟为零,并且它不显示暂停"标签.我使用 UIAnimation 来重置值而不是仅仅分配新值的一个原因是,由于某种原因,如果我不使用 UIAnimation,动画就不会停止.无论如何,这是 pauseAnimation 方法:

Here's my pauseAnimation method – resetAnimation is almost identical, except its animation call has zero duration and delay, and it doesn't show the 'Paused' label. One reason I'm using UIAnimation to reset the values instead of just assigning the new values is that for some reason, the animations just didn't stop if I didn't use UIAnimation. Anyway, here's the pauseAnimation method:

    - (void)pauseAnimation {
    if (currentAnimationPhase < 6 || currentAnimationPhase == 255) { 
            // 6 means finished, 255 is a short initial animation only showing at first launch
        self.paused = YES;
        [UIView animateWithDuration:0.3
                              delay:0 
                            options:UIViewAnimationOptionAllowUserInteraction |
         UIViewAnimationOptionBeginFromCurrentState |
         UIViewAnimationOptionCurveEaseInOut |
         UIViewAnimationOptionOverrideInheritedCurve |
         UIViewAnimationOptionOverrideInheritedDuration
                         animations:^{
                             pausedView.alpha = 1.0;
                             cameraImageView.alpha = 0;
                             mirrorGlowView.alpha = 0;
                             infoButton.alpha = 1.0;
                             chantView.alpha = 0; 
                             verseOneLabel.alpha = 1.0;
                             verseTwoLabel.alpha = 0; 
                             verseThreeLabel.alpha = 0;
                             shine1View.alpha = stars1View.alpha = stars2View.alpha = 0;
                             shine1View.transform = CGAffineTransformIdentity;
                             stars1View.transform = CGAffineTransformIdentity;
                             stars2View.transform = CGAffineTransformIdentity;
                             finishedMenuView.alpha = 0;
                             preparingMagicView.alpha = 0;}
                         completion:^(BOOL finished){
                             pausedView.alpha = 1.0;
                             cameraImageView.alpha = 0;
                             mirrorGlowView.alpha = 0;
                             infoButton.alpha = 1.0;
                             chantView.alpha = 0; 
                             verseOneLabel.alpha = 1.0;
                             verseTwoLabel.alpha = 0; 
                             verseThreeLabel.alpha = 0;
                             shine1View.alpha = stars1View.alpha = stars2View.alpha = 0;
                             shine1View.transform = CGAffineTransformIdentity;
                             stars1View.transform = CGAffineTransformIdentity;
                             stars2View.transform = CGAffineTransformIdentity;
                             finishedMenuView.alpha = 0;
                             preparingMagicView.alpha = 0;
                         }];
        askTheMirrorButton.enabled = YES; 
        againButton.enabled = NO;
        shareOnFacebookButton.enabled = NO;
        emailButton.enabled = NO;
        saveButton.enabled = NO;
        currentAnimationPhase = 0;
        [[cameraImageView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; // To remove the video preview layer
    }
}

推荐答案

此方法返回后立即截图.我猜你的 -resetAnimation 方法在下一个 runloop 循环中完成,而不是立即完成.我没有尝试过,但你可以尝试让 runloop 运行,然后稍后返回:

The screenshot is taken immediately after this method returns. I guess your -resetAnimation method completes in the next runloop cycle and not immediately. I've not tried this, but you could try to let the runloop run and then return a little bit later:

- (void) applicationDidEnterBackground:(UIApplication *)application {
    // YOUR CODE HERE

    // Let the runloop run for a brief moment
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}

我希望这会有所帮助,费边

I hope this helps, Fabian

更新:-pauseAnimation 和 -resetAnimation 的区别

方法:在-applicationWillResignActive:中延迟动画发生,在-applicationDidEnterBackground:中取消延迟动画

Approach: Delay the animation happening in -applicationWillResignActive: and cancel the delayed animation in -applicationDidEnterBackground:

- (void) applicationWillResignActive:(UIApplication *)application {
    // Measure the time between -applicationWillResignActive: and -applicationDidEnterBackground first!
    [self performSelector:@selector(pauseAnimation) withObject:nil afterDelay:0.1];

    // OTHER CODE HERE
}

- (void) applicationDidEnterBackground:(UIApplication *)application {
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(pauseAnimation) object:nil];

    // OTHER CODE HERE
}

这篇关于iOS 在进入后台时拍摄视图快照的确切时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆