Open tallytarik opened 8 years ago
Update: In particular, it seems that something about changing the status bar styles cancels the UIView animation in [DismissAnimator animateTransition:]
. The animation seems to be completely cancelled without calling the completion block and therefore [transitionContext completeTransition:]
is never called.
I have tried tracking whether or not this completion block is called, and then after a delay calling completeTransition
if the block was never called. I'm using Objective-C, so I've got the following code:
__block BOOL didComplete = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(!didComplete && [transitionContext transitionWasCancelled]) [transitionContext completeTransition:NO];
});
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromVC.view.frame = finalFrame;
} completion:^(BOOL finished) {
didComplete = YES;
[transitionContext completeTransition:!([transitionContext transitionWasCancelled])];
}];
This works but it's not great - the transition still breaks for a split second before fixing itself. :(
@ev0lution Thanks for reporting this issue and including detailed troubleshooting. I'll take a look.
@ev0lution I've been banging my head against the wall on this one, and it looks like your approach is the way to go.
I found two radars on this issue:
iOS 8.3 introduced a cross-fade animation when the status bar changes between .Default
and .LightContent
. As you explained earlier, a very quick pan will trigger cancelInteractiveTransition()
. However, since the status bar animation is still in flight, animateWithDuration
's completion
block never gets called. This means completeTransition
isn't called either, and the transition enters an inconsistent state.
According to the radar, this issue is fixed in iOS 9.3ß2. In the meantime, your workaround appears to be the way to go. It captures the transitionContext
via closure, and does the cleanup work of calling completeTransition
if the animateWithDuration
completion
block is never called.
Here are some of my failed attempts:
preferredStatusBarUpdateAnimation
to .None
in hopes of reducing the status bar animation durationsetAnimationDelegate
in hopes of hooking into an animation failure eventsetNeedsStatusBarAppearanceUpdate
in the animation
block in hopes of incorporating the status bar animation into the interactive transitionFor posterity, here are some of the more helpful links I've found surrounding on this issue:
@chenr2 Thanks so much for your time and research on this, super helpful! Good to hear that it's fixed in the latest beta, I'll check it out. :)
Is there any update on fixing this? This works very well except for when this issue presents itself.
@nevinjethmalani It's actually an iOS issue, and it's fixed in 9.3. You can use my workaround (above) for versions <9.3 if you're okay with the transition being broken for a split second. Another alternative is to set the status bar style manually, before and after the transition/view change, so that the transition isn't trying to animate the status bar style change (which is what seems to break).
We have the latest iOS installed on our devices and we are getting the same error. I will try the work around that you posted here. We are using a scrollview instead of a table view to do this maybe that is the reason.
What do you mean by set the status bar style manually? Do we have to create a navigation bar in the storyboard manually? How would we do this?
I don't know why, but it is ok for me.You can try in viewWillDisappear to reset status bar style.
Do you know if this has been fixed in iOS 10?
Totally need this so bad in my ios app Tipped, on webviews and collectionviews..... But swift 3 not working :( how to fix
Working on ios < 9.3
@interface ModalViewController ()
@property (nonatomic, assign) UIStatusBarStyle preferredStatusBarStyle;
@end
@implementation ModalViewController
@synthesize preferredStatusBarStyle;
- (void)viewDidLoad {
[super viewDidLoad];
self.preferredStatusBarStyle = UIStatusBarStyleLightContent;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.preferredStatusBarStyle = UIStatusBarStyleDefault;
[self setNeedsStatusBarAppearanceUpdate];
}
@end
I've just spent hours pulling my hair out trying to figure out why my project was exhibiting a strange bug but your project works fine, and I've finally got it! (but not how to fix it, sadly)
If you use view-controller based status bar styles (
UIViewControllerBasedStatusBarAppearance
in Info.plist), there's a nasty bug that breaks the transition and leaves the app unusable. To replicate, see the following:Try to drag down on the modal view a tiny bit very quickly (for example, drag down about 50 pixels only just clicking the mouse for a split second)
In the original project, this works as expected - the modal view snaps back to the top, you can continue to do this (or drag further down to dismiss) and the "close" button continues to function.
Now change the status bar style of one of the view controllers so that they're both different - e.g. in
ModalViewController.swift
:Run the app and try the same thing a couple of times, and the transition will break: the modal will snap back to the top but will no longer respond to the gesture recognizer, and the "close" button does not work to dismiss the modal view manually. The status bar will be stuck in the state of the presenting view controller.
This only happens when the status bar is a different style between the two view controllers, but I need this in my app, and I'm not sure how to fix it at all. :(