自定义后退指示器图像和 iOS 11

Custom back indicator image and iOS 11

我在我的应用程序中使用自定义后退按钮。这个自定义后退按钮全局设置如下:

    UINavigationBar.appearance().backIndicatorImage = UIImage(named: "Back").withRenderingMode(.alwaysOriginal)
    UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(asset: .back).withRenderingMode(.alwaysOriginal)

在 iOS 11 之前,这段代码可以解决问题,但现在在 iOS 11 中,按钮不再垂直居中,您可以在此处看到:

我可以将后退按钮图像的高度更改为 44,但这会在 iOS < 11 时破坏它。我也可以使用两个不同的图像,但我正在寻找更清晰的东西,比如在后退按钮容器视图中垂直居中图像的方法。

编辑:

原来如banxii1988所说,问题是setBackButtonTitlePositionAdjustment值故意将标题移到可见屏幕之外引起的。这是为了避免在每个视图控制器中删除后退按钮标题的黑客攻击。我决定删除这个 hack,我做了正确的事情:

  1. 将情节提要中的后退按钮项设置为" "
  2. 在每个没有关联故事板的视图控制器中,我设置 backBarButtonItem 以编程方式 navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)

请注意,您在视图控制器中看到的后退按钮标题是在导航堆栈中的前一个中设置的。

1) 移除 PositionAdjustment(如果有的话)。比如

  bap.setBackButtonTitlePositionAdjustment(UIOffset(horizontal: 0, vertical: -64), for: .default)

2) 检查导航堆栈中的前一个 ViewController 是否有标题

我觉得这个方法可以!对我有用。

if(@available(iOS 11, *)) {
    [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor clearColor]} forState:UIControlStateNormal];
    [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor clearColor]} forState:UIControlStateHighlighted];

} else {
    [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(-60, -60) forBarMetrics:UIBarMetricsDefault];
}

经过几次尝试和失败后,这对我们有用 iOS 11:

[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(-200, -5) forBarMetrics:UIBarMetricsDefault];

诀窍是将 x 轴上的 "Back" 文本向后移动很多,并在 y 轴上移动一点,因为 setBackButtonTitlePositionAdjustment 结果会同时影响图像和文字.

不过,我们不知道这个解决方案能用多久,苹果随时可能"fixed"

对于无法解决问题的任何人:

1) 在你的项目中(cmd+shift+f)搜索"setBackButtonTitle",你会找到如下代码:

[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[xController class]]] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60) forBarMetrics:UIBarMetricsDefault];

2) 用这个更改上面的代码:

[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[xController class]]] setBackButtonTitlePositionAdjustment:UIOffsetMake(-200, 0) forBarMetrics:UIBarMetricsDefault];

从 iOS 11 开始,上面的代码我们用来隐藏后退按钮标题,将后退按钮与标题本身一起移动。但是,如果你只是水平移动后退按钮标题,一切正常,没有回退。

我会推荐方法 swizzling 来解决它,我在我的一些项目中使用了这个解决方案并且效果很好。

1 - 创建类别 UIViewController

2-导入#import <objc/runtime.h>.

3-粘贴以下方法

#import "UIViewController+Extras.h"
#import <objc/runtime.h>
@implementation UIViewController (Extras)

+ (void)load {
    static dispatch_once_t once_token;
    dispatch_once(&once_token,  ^{
        SEL viewDidLoadSelector = @selector(viewDidLoad);
        SEL viewDidLoadModifyBackButtonSelector = @selector(modifyBackButton_viewDidLoad);
        Method originalMethod = class_getInstanceMethod(self, viewDidLoadSelector);
        Method extendedMethod = class_getInstanceMethod(self, viewDidLoadModifyBackButtonSelector);
        method_exchangeImplementations(originalMethod, extendedMethod);
    });
}

- (void)modifyBackButton_viewDidLoad {
    [self modifyBackButton_viewDidLoad];
    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:self.navigationItem.backBarButtonItem.style target:nil action:nil];
}

@end
if(@available(iOS 11, *)) {
    [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor clearColor]} forState:UIControlStateNormal];
    [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor clearColor]} forState:UIControlStateHighlighted];

} else {
    [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(-60, -60) forBarMetrics:UIBarMetricsDefault];
}

@Tonin 的上述解决方案有效,但唯一的问题是导航栏左按钮文本(如 "Cancel")在共享到其他应用程序(电子邮件、消息等)时是透明的(清晰的颜色),如果需要共享功能,请翻转颜色:

UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[title, URL] applicationActivities:nil];
[activityViewController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
     // set clear color when back from share
     [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor clearColor]} forState:UIControlStateNormal];
}];
[self presentViewController:activityViewController animated:YES completion:^{
     // set white color when share to other app 
     [[UIBarButtonItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor whiteColor]} forState:UIControlStateNormal];
}];

对于 SWIFT 3+

     if #available(iOS 11, *) {
            UIBarButtonItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: .normal)
            UIBarButtonItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.clear], for: .highlighted)
     } else {
            UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0,
-60), for:UIBarMetrics.default)
        }

此解决方案适用于 iOS 9、10 和 11

    var backButtonImage: UIImage = UIImage(named: "backButton")!
    UINavigationBar.appearance().backIndicatorImage = backButtonImage
    UINavigationBar.appearance().backIndicatorTransitionMaskImage = backButtonImage

    if #available(iOS 11, *) {
        UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(-300, 0), for:UIBarMetrics.default)
    } else {
        UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -200), for:UIBarMetrics.default)
    }

1.

extension UINavigationController {
    func pushViewC(_ viewController: UIViewController, animated: Bool) {
        viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "return").withRenderingMode(.alwaysOriginal), style: .plain, target: navigationController, action: #selector(popViewController(animated:)))
        pushViewController(viewController, animated: animated)
    }
}

2.use pushViewC 而不是 pushViewController

navigationController?.pushViewC(otherVC, animated: true)