前言
关于实现 App 全局统一样式的返回按钮,之前我们通过修改 [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:]
来改变返回按钮中文字的偏移量,来实现隐藏文字的效果。但是改完后不是很满意,给大家两张图感受一下
←iOS10 ←iOS11
很明显,iOS 11以下,即使隐藏了文字,但是如果原本文字过长依旧会出现标题被挤到右侧的情况,而iOS 11,文字会从偏移后的位置出现或消失,正常动画时间下会有种很突兀的感觉。正好在这时,产品在新项目中提了个要求,返回按钮默认文字为“返回”,而不再是隐藏。那么如果我们能够实现修改默认返回按钮文字,只要设置文字为@" "也能达到隐藏的目的,一举两得!那么就来试试能不能修改默认值吧。
思路
首先来看看UIBarButtonItem
的相关Api,有没有能修改默认文字的方法。嗯……没找到………… 再找找UINavigationBar
的相关Api,嗯……还是没找到………… 再看看UINavigationItem
呢,嗯……还是找不到……接下来只能找产品改掉这个无理需求了
好吧,既然我们没法直接用苹果的Api搞定,那就自己来实现吧。很显然,无法调用外部Api就需要我们重写一些方法了,分类+runtime黑魔法是个很不错的方式。(什么?你说用继承?继承当然也可以实现,但是这种一点都不高大上,还要重新调整之前项目中旧代码的方式很明显第一时间就被我摒弃了。)所以接下来我们需要寻找关键的方法,然后通过重写来实现效果。
写之前我们先来回忆一下UINavigationBar
中的UINavigationItem
和UIBarButtonItem
:
UINavigationBar
中的返回按钮以及标题、右侧按钮等控件都是由UINavigationItem
属性来决定的,因此如果要修改这些内容,我们需要修改对应的UINavigationItem
。
在一个UINavigationController
中的视图控制器做切换的时候,UINavigationBar
是顶部导航栏视图,它始终是唯一的。大家都知道UINavigationController
通过栈的方式来管理视图控制器的,同样UINavigationBar
也是通过栈的方式来管理不同的UINavigationItem
。
UINavigationItem
中的左侧按钮有两种:backBarButtonItem
和leftBarButtonItem
,虽然都能改变左侧按钮但是区别较大。
backBarButtonItem
属性决定的是下一个视图返回当前视图的按钮,即设置A视图的UINavigationItem.backBarButtonItem
,需要进入下一个B视图时,显示在左侧,不需要实现相应的点击事件;leftBarButtonItem
属性可以直接更改当前视图导航栏的左侧按钮,替代掉前一个视图的backBarButtonItem
,需要自己实现点击事件,同时会关闭侧滑手势。
既然我们要修改默认返回按钮,那么直接修改backBarButtonItem
就可以了。
这里请注意,我们修改的是‘默认’值,也就是缺省值。如果代码中单独设置了
backBarButtonItem
,我们不能去改变这个值。
代码
说了这么多,直接来看实现:
- 新建
UINavigationItem
的分类
#import <UIKit/UIKit.h>
@interface UINavigationItem (BackItem)
@end
复制代码
- 导入runtime头文件,重写
backBarButtonItem
的getter方法
#import "UINavigationItem+BackItem.h"
#import <objc/runtime.h>
@implementation UINavigationItem (BackItem)
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalMethodImp = class_getInstanceMethod(self, @selector(backBarButtonItem));
Method destMethodImp = class_getInstanceMethod(self, @s