Skip to content

Commit

Permalink
fix: 移除 ViewControllers 中 rootViewController 之后,新的 rootViewController…
Browse files Browse the repository at this point in the history
… 返回按钮显示不正确问题 #16
  • Loading branch information
l1Dan committed Apr 20, 2023
1 parent c4d0a46 commit 1f76051
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,12 @@ + (void)load {
viewControllers = [NSOrderedSet orderedSetWithArray:viewControllers].array; // 这里会保留该 vc 第一次出现的位置不变
}

// setViewControllers 执行前后 topViewController 没有变化,则赋值为 nil,表示没有任何界面有“重新显示”。
UIViewController *appearingViewController = selfObject.topViewController != viewControllers.lastObject ? viewControllers.lastObject : nil;
[selfObject nx_processViewController:appearingViewController navigationAction:NXNavigationActionWillSet];

callSuperBlock();

for (UIViewController *viewController in viewControllers) {
viewController.navigationItem.nx_viewController = viewController;
// 先赋值一次
Expand All @@ -317,14 +323,13 @@ + (void)load {
// 重新检查返回手势是否动态修改
[selfObject nx_configureInteractivePopGestureRecognizerWithViewController:viewController];
}
} else {
// 处理 rootViewController
[selfObject nx_configureNavigationBarWithNavigationController:selfObject];
// 在 rootViewController 中禁止使用返回手势
[selfObject nx_resetInteractivePopGestureRecognizer];
}

// setViewControllers 执行前后 topViewController 没有变化,则赋值为 nil,表示没有任何界面有“重新显示”。
UIViewController *appearingViewController = selfObject.topViewController != viewControllers.lastObject ? viewControllers.lastObject : nil;
[selfObject nx_processViewController:appearingViewController navigationAction:NXNavigationActionWillSet];

callSuperBlock();

[selfObject nx_processViewController:appearingViewController navigationAction:NXNavigationActionDidSet];
[selfObject nx_animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
NXNavigationAction navigationAction = context.isCancelled ? NXNavigationActionSetCancelled : NXNavigationActionSetCompleted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,6 @@ - (void)nx_configureNXNavigationBar {
self.nx_navigationBarInitialize = YES;
// 调用外部配置信息
[self nx_executePrepareConfigurationViewControllerCallback];
// fix: 修复 popToRootViewController 时调用 nx_setNeedsNavigationBarAppearanceUpdate 方法会设置 leftBarButtonItem 的问题
[self.navigationController viewControllers].firstObject.nx_isRootViewController = YES;
[self.navigationController nx_configureNavigationBar];
[self nx_setupNavigationBar];
[self nx_updateNavigationBarAppearance];
Expand Down Expand Up @@ -438,20 +436,6 @@ - (void)setNx_navigationVirtualWrapperView:(NXNavigationVirtualWrapperView *)nx_
objc_setAssociatedObject(self, @selector(nx_navigationVirtualWrapperView), nx_navigationVirtualWrapperView, OBJC_ASSOCIATION_ASSIGN);
}

- (NXNavigationAction)nx_navigationAction {
NSNumber *number = objc_getAssociatedObject(self, _cmd);
if (!number || ![number isKindOfClass:[NSNumber class]]) {
NXNavigationAction navigationAction = NXNavigationActionUnspecified;
[self setNx_navigationAction:navigationAction];
return navigationAction;
}
return [number integerValue];
}

- (void)setNx_navigationAction:(NXNavigationAction)nx_navigationAction {
objc_setAssociatedObject(self, @selector(nx_navigationAction), @(nx_navigationAction), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NXNavigationBar *)nx_navigationBar {
// 如果之前已经创建过 NXNavigationBar 实例,则直接返回原来已经创建好的实例对象。
NXNavigationBar *bar = objc_getAssociatedObject(self, _cmd);
Expand Down Expand Up @@ -590,9 +574,8 @@ - (void)nx_setNeedsNavigationBarAppearanceUpdate {
[self.navigationController nx_adjustmentSystemBackButtonForViewController:self inViewControllers:previousViewControllers];
}

if (!self.nx_isRootViewController) {
[self nx_configureNavigationBarWithNavigationController:self.navigationController];
}
[self nx_configureNavigationBarWithNavigationController:self.navigationController];

// 重新检查返回手势是否动态修改
[self.navigationController nx_configureInteractivePopGestureRecognizerWithViewController:self];
}
Expand Down
12 changes: 9 additions & 3 deletions NXNavigationExtension/Private/NXNavigationExtensionInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ typedef void (^UIViewControllerDidUpdateFrameHandler)(UIViewController *viewCont

@end

@interface NXBackButtonItem : UIBarButtonItem

@end


/// 全屏滑动返回手势代理
@interface NXFullScreenPopGestureRecognizerDelegate : NSObject <UIGestureRecognizerDelegate>

Expand Down Expand Up @@ -119,6 +124,10 @@ typedef void (^UIViewControllerDidUpdateFrameHandler)(UIViewController *viewCont
/// 配置 NXNavigationBar
- (void)nx_configureNavigationBar;


/// 重置返回手势
- (void)nx_resetInteractivePopGestureRecognizer;

/// 配置返回手势
- (void)nx_configureInteractivePopGestureRecognizerWithViewController:(__kindof UIViewController *)viewController;

Expand Down Expand Up @@ -160,9 +169,6 @@ typedef void (^UIViewControllerDidUpdateFrameHandler)(UIViewController *viewCont
/// 获取当前视图控制器转场周期事件
@property (nonatomic, assign) NXNavigationAction nx_navigationAction;

/// 记录当前视图控制器是否为导航控制器的 rootViewController
@property (nonatomic, assign) BOOL nx_isRootViewController;

/// 记录是否为 childViewControllers 中的控制器,并且当前控制器不是 UINavigationController 的情况下。
@property (nonatomic, assign) BOOL nx_isChildViewController;

Expand Down
79 changes: 44 additions & 35 deletions NXNavigationExtension/Private/NXNavigationExtensionInternal.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#import "UINavigationController+NXNavigationExtension.h"
#import "UIViewController+NXNavigationExtension.h"

@implementation NXBackButtonItem

@end


@implementation NXScreenEdgePopGestureRecognizerDelegate

Expand Down Expand Up @@ -382,6 +386,11 @@ - (void)nx_setupInteractivePopGestureRecognizer {
self.interactivePopGestureRecognizer.delegate = self.nx_screenEdgePopGestureDelegate;
}

- (void)nx_resetInteractivePopGestureRecognizer {
self.interactivePopGestureRecognizer.enabled = NO;
self.nx_fullScreenPopGestureRecognizer.enabled = NO;
}

- (void)nx_configureInteractivePopGestureRecognizerWithViewController:(__kindof UIViewController *)viewController {
if (!self.interactivePopGestureRecognizer) return;

Expand Down Expand Up @@ -443,15 +452,15 @@ - (void)nx_adjustmentSystemBackButtonForViewController:(__kindof UIViewControlle
if (currentViewController.nx_systemBackButtonTitle) {
// 去掉前后空格
NSString *title = [currentViewController.nx_systemBackButtonTitle stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:nil action:nil];
NXBackButtonItem *backItem = [[NXBackButtonItem alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:nil action:nil];
if ([title isEqualToString:@""]) {
if (@available(iOS 14.0, *)) {
/**
* #1
* lastViewController.navigationItem.backBarButtonItem = nil; 恢复系统返回按钮默认样式。长按返回按钮还会出现上一级导航栏的标题
* lastViewController.navigationItem.backButtonDisplayMode = UINavigationItemBackButtonDisplayModeMinimal; 隐藏返回按钮标题
* #2
* UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; // 隐藏返回按钮标题
* NXBackButtonItem *backItem = [[NXBackButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; // 隐藏返回按钮标题
* lastViewController.navigationItem.backBarButtonItem = backItem; 长按返回按钮将无法出现上一级导航栏的标题
*/
lastViewController.navigationItem.backBarButtonItem = nil;
Expand Down Expand Up @@ -543,26 +552,20 @@ - (void)nx_processViewController:(__kindof UIViewController *)appearingViewContr
@end


@interface UIViewController (NXNavigationExtensionInternal)

/// 记录自定义返回按钮对象,用于后续对比是否为同一个对象
@property (nonatomic, strong) UIBarButtonItem *nx_customBackButtonItem;

@end


@implementation UIViewController (NXNavigationExtensionInternal)

- (BOOL)nx_isRootViewController {
- (NXNavigationAction)nx_navigationAction {
NSNumber *number = objc_getAssociatedObject(self, _cmd);
if (number && [number isKindOfClass:[NSNumber class]]) {
return [number boolValue];
if (!number || ![number isKindOfClass:[NSNumber class]]) {
NXNavigationAction navigationAction = NXNavigationActionUnspecified;
[self setNx_navigationAction:navigationAction];
return navigationAction;
}
return NO;
return [number integerValue];
}

- (void)setNx_isRootViewController:(BOOL)nx_isRootViewController {
objc_setAssociatedObject(self, @selector(nx_isRootViewController), @(nx_isRootViewController), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (void)setNx_navigationAction:(NXNavigationAction)nx_navigationAction {
objc_setAssociatedObject(self, @selector(nx_navigationAction), @(nx_navigationAction), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)nx_isChildViewController {
Expand All @@ -589,14 +592,6 @@ - (void)nx_triggerSystemPopViewController {
}];
}

- (UIBarButtonItem *)nx_customBackButtonItem {
return objc_getAssociatedObject(self, _cmd);
}

- (void)setNx_customBackButtonItem:(UIBarButtonItem *)nx_customBackButtonItem {
objc_setAssociatedObject(self, @selector(nx_customBackButtonItem), nx_customBackButtonItem, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id<NXNavigationControllerDelegate>)nx_navigationControllerDelegate {
return objc_getAssociatedObject(self, _cmd);
}
Expand Down Expand Up @@ -634,36 +629,50 @@ - (void)setNx_prepareConfigureViewControllerCallback:(NXViewControllerPrepareCon

- (void)nx_configureNavigationBarWithNavigationController:(__kindof UINavigationController *)navigationController {
[self.navigationItem setHidesBackButton:!self.nx_useSystemBackButton animated:NO];

// 统一处理 rootViewController 发生改变的情况
UIViewController *rootViewController = [navigationController.viewControllers firstObject];
if (rootViewController) {
UIBarButtonItem *backButton = rootViewController.navigationItem.leftBarButtonItem;
if (backButton && [backButton isKindOfClass:[NXBackButtonItem class]]) {
rootViewController.navigationItem.leftBarButtonItem = nil;
}
// 当前控制器为 rootViewController 则不需要处理
if (self == rootViewController) {
return;
}
}

// 使用系统返回按钮时移除自定义返回按钮
if (self.nx_useSystemBackButton) {
UIBarButtonItem *customBackButtonItem = self.nx_customBackButtonItem;
UIBarButtonItem *leftBarButtonItem = self.navigationItem.leftBarButtonItem;
// 如果导航栏不同时支持返回按钮和 leftItems 则清空 left 区域,或者 left 为自定义返回按钮也要清空。
if (!self.navigationItem.leftItemsSupplementBackButton ||
(customBackButtonItem && leftBarButtonItem && customBackButtonItem == leftBarButtonItem)) {
self.navigationItem.leftBarButtonItem = nil;
self.navigationItem.leftBarButtonItems = nil;
UIBarButtonItem *backButton = self.navigationItem.leftBarButtonItem;
if (backButton && [backButton isKindOfClass:[NXBackButtonItem class]]) {
rootViewController.navigationItem.leftBarButtonItem = nil;
}
return;
}

// 仅当 leftBarButtonItem 为 nil 的情况才添加返回按钮
UIBarButtonItem *backButtonItem = self.navigationItem.leftBarButtonItem;
if (backButtonItem) {
return;
}

UIView *customView = self.nx_backButtonCustomView;
if (customView) {
backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customView];
backButtonItem = [[NXBackButtonItem alloc] initWithCustomView:customView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(nx_triggerSystemPopViewController)];
customView.semanticContentAttribute = navigationController.navigationBar.semanticContentAttribute;
customView.userInteractionEnabled = YES;
[customView addGestureRecognizer:tap];
self.nx_customBackButtonItem = backButtonItem;
} else {
BOOL isRightToLeft = navigationController.navigationBar.semanticContentAttribute == UISemanticContentAttributeForceRightToLeft;
SEL selector = @selector(nx_triggerSystemPopViewController);
UIImage *backImage = isRightToLeft ? self.nx_backImage.imageFlippedForRightToLeftLayoutDirection : self.nx_backImage;
UIImage *landscapeBackImage = isRightToLeft ? self.nx_landscapeBackImage.imageFlippedForRightToLeftLayoutDirection : self.nx_landscapeBackImage;
backButtonItem = [[UIBarButtonItem alloc] initWithImage:backImage landscapeImagePhone:landscapeBackImage style:UIBarButtonItemStylePlain target:self action:selector];
backButtonItem = [[NXBackButtonItem alloc] initWithImage:backImage landscapeImagePhone:landscapeBackImage style:UIBarButtonItemStylePlain target:self action:selector];
backButtonItem.imageInsets = NXDirectionalEdgeInsetsMake(self.nx_backImageInsets, navigationController.navigationBar.semanticContentAttribute);
backButtonItem.landscapeImagePhoneInsets = NXDirectionalEdgeInsetsMake(self.nx_landscapeBackImageInsets, navigationController.navigationBar.semanticContentAttribute);
self.nx_customBackButtonItem = backButtonItem;
}
self.navigationItem.leftBarButtonItem = backButtonItem;
}
Expand Down

0 comments on commit 1f76051

Please sign in to comment.