@@ -33,6 +33,32 @@ @interface _QMUITransitionNavigationBar : UINavigationBar
3333
3434@implementation _QMUITransitionNavigationBar
3535
36+ + (void )load {
37+ static dispatch_once_t onceToken;
38+ dispatch_once (&onceToken, ^{
39+ // TODO: molice iOS 14 正式版发布后检查
40+ // iOS 14 Beta 6 开启 customNavigationBarTransitionKey 的情况下转场效果错误
41+ // https://github.com/Tencent/QMUI_iOS/issues/1081
42+ if (@available (iOS 14.0 , *)) {
43+ OverrideImplementation ([_QMUITransitionNavigationBar class ], NSSelectorFromString ([NSString stringWithFormat: @" _%@ _%@ " , @" accessibility" , @" navigationController" ]), ^id (__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void )) {
44+ return ^UINavigationController *(_QMUITransitionNavigationBar *selfObject) {
45+ if (selfObject.originalNavigationBar ) {
46+ BeginIgnorePerformSelectorLeaksWarning
47+ return [selfObject.originalNavigationBar performSelector: originCMD];
48+ EndIgnorePerformSelectorLeaksWarning
49+ }
50+
51+ // call super
52+ UINavigationController *(*originSelectorIMP)(id , SEL );
53+ originSelectorIMP = (UINavigationController *(*)(id , SEL ))originalIMPProvider ();
54+ UINavigationController *result = originSelectorIMP (selfObject, originCMD);
55+ return result;
56+ };
57+ });
58+ }
59+ });
60+ }
61+
3662- (void )setOriginalNavigationBar : (UINavigationBar *)originBar {
3763 _originalNavigationBar = originBar;
3864
@@ -208,40 +234,34 @@ + (void)load {
208234
209235 OverrideImplementation ([UIViewController class ], @selector (viewWillLayoutSubviews ), ^id (__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void )) {
210236 return ^(UIViewController *selfObject) {
237+ id <UIViewControllerTransitionCoordinator> transitionCoordinator = selfObject.transitionCoordinator ;
238+ UIViewController *fromViewController = [transitionCoordinator viewControllerForKey: UITransitionContextFromViewControllerKey];
239+ UIViewController *toViewController = [transitionCoordinator viewControllerForKey: UITransitionContextToViewControllerKey];
211240
212- if (selfObject.navigationController .delegate && ![selfObject.navigationController.delegate respondsToSelector: @selector (navigationController:animationControllerForOperation:fromViewController:toViewController: )]) {
213-
214- id <UIViewControllerTransitionCoordinator> transitionCoordinator = selfObject.transitionCoordinator ;
215- UIViewController *fromViewController = [transitionCoordinator viewControllerForKey: UITransitionContextFromViewControllerKey];
216- UIViewController *toViewController = [transitionCoordinator viewControllerForKey: UITransitionContextToViewControllerKey];
241+ BOOL isCurrentToViewController = (selfObject == selfObject.navigationController .viewControllers .lastObject && selfObject == toViewController);
242+
243+ if (isCurrentToViewController && !selfObject.lockTransitionNavigationBar ) {
217244
218- BOOL isCurrentToViewController = (selfObject == selfObject. navigationController . viewControllers . lastObject && selfObject == toViewController) ;
245+ BOOL shouldCustomNavigationBarTransition = NO ;
219246
220- if (isCurrentToViewController && !selfObject.lockTransitionNavigationBar ) {
221-
222- BOOL shouldCustomNavigationBarTransition = NO ;
223-
224- if (!selfObject.transitionNavigationBar ) {
225-
226- if ([selfObject shouldCustomTransitionAutomaticallyWithFirstViewController: fromViewController secondViewController: toViewController]) {
227- shouldCustomNavigationBarTransition = YES ;
228- }
229-
230- if (shouldCustomNavigationBarTransition) {
231- if (selfObject.navigationController .navigationBar .translucent ) {
232- // 如果原生bar是半透明的,需要给containerView加个背景色,否则有可能会看到下面的默认黑色背景色
233- toViewController.originContainerViewBackgroundColor = [transitionCoordinator containerView ].backgroundColor ;
234- [transitionCoordinator containerView ].backgroundColor = [selfObject containerViewBackgroundColor ];
235- }
236- [selfObject addTransitionNavigationBarIfNeeded ];
237- [selfObject resizeTransitionNavigationBarFrame ];
238- selfObject.navigationController .navigationBar .transitionNavigationBar = selfObject.transitionNavigationBar ;
239- selfObject.prefersNavigationBarBackgroundViewHidden = YES ;
247+ if (!selfObject.transitionNavigationBar ) {
248+ UINavigationControllerOperation operation = toViewController.navigationController .topViewController == toViewController ? UINavigationControllerOperationPush: UINavigationControllerOperationPop;
249+ if ([selfObject shouldCustomTransitionAutomaticallyForOperation: operation firstViewController: fromViewController secondViewController: toViewController]) {
250+ shouldCustomNavigationBarTransition = YES ;
251+ }
252+ if (shouldCustomNavigationBarTransition) {
253+ if (selfObject.navigationController .navigationBar .translucent ) {
254+ // 如果原生bar是半透明的,需要给containerView加个背景色,否则有可能会看到下面的默认黑色背景色
255+ toViewController.originContainerViewBackgroundColor = [transitionCoordinator containerView ].backgroundColor ;
256+ [transitionCoordinator containerView ].backgroundColor = [selfObject containerViewBackgroundColor ];
240257 }
258+ [selfObject addTransitionNavigationBarIfNeeded ];
259+ [selfObject resizeTransitionNavigationBarFrame ];
260+ selfObject.navigationController .navigationBar .transitionNavigationBar = selfObject.transitionNavigationBar ;
261+ selfObject.prefersNavigationBarBackgroundViewHidden = YES ;
241262 }
242263 }
243264 }
244-
245265 // call super
246266 void (*originSelectorIMP)(id , SEL );
247267 originSelectorIMP = (void (*)(id , SEL ))originalIMPProvider ();
@@ -443,7 +463,7 @@ - (BOOL)hideNavigationBarWhenTransitioning {
443463 return NO ;
444464}
445465
446- - (BOOL )shouldCustomTransitionAutomaticallyWithFirstViewController : (UIViewController *)viewController1 secondViewController : (UIViewController *)viewController2 {
466+ - (BOOL )shouldCustomTransitionAutomaticallyForOperation : (UINavigationControllerOperation) operation firstViewController : (UIViewController *)viewController1 secondViewController : (UIViewController *)viewController2 {
447467
448468 UIViewController<QMUINavigationControllerDelegate> *vc1 = (UIViewController<QMUINavigationControllerDelegate> *)viewController1;
449469 UIViewController<QMUINavigationControllerDelegate> *vc2 = (UIViewController<QMUINavigationControllerDelegate> *)viewController2;
@@ -452,6 +472,15 @@ - (BOOL)shouldCustomTransitionAutomaticallyWithFirstViewController:(UIViewContro
452472 return NO ;// 只处理前后两个界面都是 QMUI 系列的场景
453473 }
454474
475+ if ([vc1.navigationController.delegate respondsToSelector: @selector (navigationController:animationControllerForOperation:fromViewController:toViewController: )]) {
476+ // 说明可能有自定义的系统转场动画
477+ BOOL a = [vc1 respondsToSelector: @selector (shouldCustomizeNavigationBarTransitionIfUsingCustomTransitionForOperation:fromViewController:toViewController: )] ? [vc1 shouldCustomizeNavigationBarTransitionIfUsingCustomTransitionForOperation: operation fromViewController: vc1 toViewController: vc2] : NO ;
478+ BOOL b = [vc2 respondsToSelector: @selector (shouldCustomizeNavigationBarTransitionIfUsingCustomTransitionForOperation:fromViewController:toViewController: )] ? [vc2 shouldCustomizeNavigationBarTransitionIfUsingCustomTransitionForOperation: operation fromViewController: vc1 toViewController: vc2] : NO ;
479+ if (!a && !b) {
480+ return NO ;
481+ }
482+ }
483+
455484 if ([vc1 respondsToSelector: @selector (customNavigationBarTransitionKey )] || [vc2 respondsToSelector: @selector (customNavigationBarTransitionKey )]) {
456485 NSString *key1 = [vc1 respondsToSelector: @selector (customNavigationBarTransitionKey )] ? [vc1 customNavigationBarTransitionKey ] : nil ;
457486 NSString *key2 = [vc2 respondsToSelector: @selector (customNavigationBarTransitionKey )] ? [vc2 customNavigationBarTransitionKey ] : nil ;
@@ -463,6 +492,8 @@ - (BOOL)shouldCustomTransitionAutomaticallyWithFirstViewController:(UIViewContro
463492 return NO ;
464493 }
465494
495+
496+
466497 UIImage *bg1 = [vc1 respondsToSelector: @selector (navigationBarBackgroundImage )] ? [vc1 navigationBarBackgroundImage ] : [[UINavigationBar appearance ] backgroundImageForBarMetrics: UIBarMetricsDefault];
467498 UIImage *bg2 = [vc2 respondsToSelector: @selector (navigationBarBackgroundImage )] ? [vc2 navigationBarBackgroundImage ] : [[UINavigationBar appearance ] backgroundImageForBarMetrics: UIBarMetricsDefault];
468499 if (bg1 || bg2) {
@@ -559,19 +590,14 @@ + (void)load {
559590 originSelectorIMP (selfObject, originCMD, aViewController, aAnimated);
560591 };
561592
562- if ([selfObject.delegate respondsToSelector: @selector (navigationController:animationControllerForOperation:fromViewController:toViewController: )]) {
563- callSuperBlock (viewController, animated);
564- return ;
565- }
566-
567593 UIViewController *disappearingViewController = selfObject.viewControllers .lastObject ;
568594 if (!disappearingViewController) {
569595 callSuperBlock (viewController, animated);
570596 return ;
571597 }
572598
573- BOOL shouldCustomNavigationBarTransition = [selfObject shouldCustomTransitionAutomaticallyWithFirstViewController: disappearingViewController secondViewController: viewController];
574-
599+ BOOL shouldCustomNavigationBarTransition =
600+ [selfObject shouldCustomTransitionAutomaticallyForOperation: UINavigationControllerOperationPush firstViewController: disappearingViewController secondViewController: viewController];
575601 if (shouldCustomNavigationBarTransition) {
576602 [disappearingViewController addTransitionNavigationBarIfNeeded ];
577603 disappearingViewController.prefersNavigationBarBackgroundViewHidden = YES ;
@@ -655,20 +681,14 @@ + (void)load {
655681}
656682
657683- (void )handlePopViewControllerNavigationBarTransitionWithDisappearViewController : (UIViewController *)disappearViewController appearViewController : (UIViewController *)appearViewController {
658-
659- if (self.delegate && ![self .delegate respondsToSelector: @selector (navigationController:animationControllerForOperation:fromViewController:toViewController: )]) {
660-
661- BOOL shouldCustomNavigationBarTransition = [self shouldCustomTransitionAutomaticallyWithFirstViewController: disappearViewController secondViewController: appearViewController];
662-
663- if (shouldCustomNavigationBarTransition) {
664- [disappearViewController addTransitionNavigationBarIfNeeded ];
665- if (appearViewController.transitionNavigationBar ) {
666- // 假设从A→B→C,其中A设置了bar的样式,B跟随A所以B里没有设置bar样式的代码,C又把样式改为另一种,此时从C返回B时,由于B没有设置bar的样式的代码,所以bar的样式依然会保留C的,这就错了,所以每次都要手动改回来才保险
667- [UIViewController replaceStyleForNavigationBar: appearViewController.transitionNavigationBar withNavigationBar: self .navigationBar];
668- }
669- disappearViewController.prefersNavigationBarBackgroundViewHidden = YES ;
684+ BOOL shouldCustomNavigationBarTransition = [self shouldCustomTransitionAutomaticallyForOperation: UINavigationControllerOperationPop firstViewController: disappearViewController secondViewController: appearViewController];
685+ if (shouldCustomNavigationBarTransition) {
686+ [disappearViewController addTransitionNavigationBarIfNeeded ];
687+ if (appearViewController.transitionNavigationBar ) {
688+ // 假设从A→B→C,其中A设置了bar的样式,B跟随A所以B里没有设置bar样式的代码,C又把样式改为另一种,此时从C返回B时,由于B没有设置bar的样式的代码,所以bar的样式依然会保留C的,这就错了,所以每次都要手动改回来才保险
689+ [UIViewController replaceStyleForNavigationBar: appearViewController.transitionNavigationBar withNavigationBar: self .navigationBar];
670690 }
671-
691+ disappearViewController. prefersNavigationBarBackgroundViewHidden = YES ;
672692 }
673693}
674694
0 commit comments