最近老板有個(gè)需求,需要把項(xiàng)目中所有的線條都給去掉,包括導(dǎo)航欄上的那根黑線,本來這個(gè)需求也很正常.可是我們的項(xiàng)目時(shí)間比較久遠(yuǎn)了,所以有的控制器繼承了基類,而有的則沒有,難道我需要在每個(gè)控制器里面都寫一遍隱藏的代碼么?特別是在一個(gè)需求多變的公司,假如哪次老板說需要這條線了,那我得重來一次么.不過我不不太喜歡寫重復(fù)性的代碼,所以就開始著手解決這件事了.
第一種:
由于1px的黑色線條是個(gè)黑色陰影圖片,所以我們可以通過設(shè)置這張圖片去讓它隱藏或者更換顏色.
①全局設(shè)置
//兩句話需要配合使用才有效
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"white.jpg"] forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setShadowImage:[UIImage new]];
這是一種比較官方的一種寫法,不過這種方法會(huì)修改navigationBar的translucent(半透明)
屬性,這個(gè)屬性會(huì)影響到我們的界面布局.
接下來我通過一個(gè)demo去驗(yàn)證它,我創(chuàng)建了兩個(gè)ViewController
,分別對應(yīng)兩個(gè)UINavigationController
.FirstVC采用了StoryBoard生成的界面,而ThirdVC則是通過代碼生成的,當(dāng)我們在AppDelegate.m
中使用了上述方法后:
從圖片我們可以發(fā)現(xiàn),使用了修改圖片來達(dá)到隱藏線條的目的是完全可行的.但是,在SB中可能不會(huì)有太 大影響,不過在非SB的布局中,我們發(fā)現(xiàn)view的渲染是從導(dǎo)航欄的底部開始的,也是說View的Y點(diǎn)為64,所以說在該視圖上的控件的Frame也會(huì)改變.如果說我們在該界面有一個(gè)隱藏和顯示導(dǎo)航欄的操作,出現(xiàn)的后果則是:
//導(dǎo)航欄顯示下的Frame
self.view.frame = CGRectMake(0, 64, 375, 603);
//導(dǎo)航欄隱藏下的Frame
self.view.frame = CGRectMake(0, 0, 375, 667);
不過既然是問題,那就有解決的辦法,我們可以通過設(shè)置translucent
為YES
就可以解決了,這時(shí)候View的布局會(huì)充滿全屏.
②單頁面設(shè)置
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"white.jpg"] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"white.jpg"] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:nil];
}
第二種:
由于第一種的方法讓我項(xiàng)目中的VC出現(xiàn)了各種各樣的問題,而我又不想一個(gè)個(gè)去改,所以又有了接下來的辦法.我們可以通過遍歷導(dǎo)航欄的子控件,尋找到這個(gè)黑色線條,在合適的時(shí)候隱藏或者顯示,這時(shí)候我們就不會(huì)改變UINavigationBar
的translucent
了,也不會(huì)影響我們視圖的布局.
①單頁面設(shè)置
在viewWillAppear:
或者viewWillDisappear:
中調(diào)用hideNavigationBarBottomLine:
方法就可以完成對線條的隱藏或顯示.
-(void)hideNavigationBarBottomLine:(BOOL)hidden{
//iOS10及以上的隱藏方法
if ([UIDevice currentDevice].systemVersion.floatValue >= 10.0) {
if ([self.navigationController.navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]) {
NSArray *list=self.navigationController.navigationBar.subviews;
for (id obj in list) {
//10.0的系統(tǒng)字段不一樣
UIView *view = (UIView*)obj;
for (id obj2 in view.subviews) {
if ([obj2 isKindOfClass:[UIImageView class]]) {
UIImageView *image = (UIImageView*)obj2;
if (image.frame.size.height <= 1) {
image.hidden = hidden;
}
}
if ([obj2 isKindOfClass:[UIView class]]) {
UIView *view2 = (UIView *)obj2;
if (view2.frame.size.height <= 1) {
view2.hidden = hidden;
}
}
}
}
}
return;
}
//iOS10以下的隱藏方法
if ([self.navigationController.navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]){
NSArray *list = self.navigationController.navigationBar.subviews;
for (id obj in list) {
if ([obj isKindOfClass:[UIImageView class]]) {
UIImageView *imageView = (UIImageView *)obj;
NSArray *list2 = imageView.subviews;
for (id obj2 in list2) {
if ([obj2 isKindOfClass:[UIImageView class]]) {
UIImageView *imageView2 = (UIImageView *)obj2;
if (imageView2.frame.size.height <= 1) {
imageView2.hidden = hidden;
}
}
if ([obj2 isKindOfClass:[UIView class]]) {
UIView *view2 = (UIView *)obj2;
if (view2.frame.size.height <= 1) {
view2.hidden = hidden;
}
}
}
}
}
}
}
②最終方案(全局設(shè)置)
but,之前提過,因?yàn)椴幌雽懼貜?fù)性的代碼,所以才來折騰的,當(dāng)時(shí)就想,如果項(xiàng)目中所有的類都繼承了基類該多好啊,在基類的viewWillAppear:
或者viewWillDisappear:
中改一次就好了.想到這里,我突然想起來有一個(gè)方法可以每次都能調(diào)用這些方法,那就是runtime
.我們可以寫一個(gè)UIViewController
的類別,通過runtime
我們可以獲取到UIViewController
生命周期方法,在viewDidLoad
中,我們只用寫一次代碼就可以了,后續(xù)的視圖控制器只要在生命周期中,都會(huì)到類別中去掉用隱藏的方法,方便又快捷,不要寫大量重復(fù)性的代碼.并且哪次老板需要顯示線條的時(shí)候,只要把這個(gè)類別移除就可以了,不用涉及到項(xiàng)目中其他類的操作.對于oc運(yùn)行時(shí)特性不了解的自行百度,具體的實(shí)現(xiàn)思路如下:
通過重寫NSObject類都有的Load方法,使用runtime
替換系統(tǒng)的viewDidLoad
方法為自己的hide_viewDidLoad
方法.
+(void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector1 = @selector(viewDidLoad);
SEL swizzledSelector1 = @selector(hide_viewDidLoad);
Method originalMethod1 = class_getInstanceMethod(class, originalSelector1);
Method swizzledMethod1 = class_getInstanceMethod(class, swizzledSelector1);
BOOL didAddMethod =
class_addMethod(class,
originalSelector1,
method_getImplementation(swizzledMethod1),
method_getTypeEncoding(swizzledMethod1));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector1,
method_getImplementation(originalMethod1),
method_getTypeEncoding(originalMethod1));
} else {
method_exchangeImplementations(originalMethod1, swizzledMethod1);
}
});
}
在替換的方法中寫我們相應(yīng)的需求:
-(void)hide_viewDidLoad {
[self hide_viewDidLoad];
if (self.navigationController) {
[self hideNavigationBarBottomLine:YES];
}
}