iOS10.0適配-導(dǎo)航欄問題

最近ios10.0發(fā)布,發(fā)現(xiàn)app在系統(tǒng)10.0下運(yùn)行,導(dǎo)航欄出現(xiàn)了若干bug,遂著手解決之。

1.復(fù)現(xiàn):

在ios9及以下的系統(tǒng)中無問題,但是在ios10.0下會(huì)出現(xiàn)如下bug(返回按鈕和titleView都不顯示):

返回按鈕及titleView都不顯示

項(xiàng)目中使用了UINavigationBar + Extension擴(kuò)展,通過對(duì)UINavigationBar添加子視圖的方式設(shè)置背景圖。

使用的源碼如下:

-(void)ls_setBackgroundColor:(UIColor *)backgroundColor{

if (!self.overlay) {

[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];

//導(dǎo)航欄下面有一條1像素高的灰色的線,這是一張圖片,可能過設(shè)置shadowImage修改

self.shadowImage = [UIImage new];

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width, CGRectGetHeight(self.bounds) + 20)];

self.overlay.userInteractionEnabled = NO;

self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self insertSubview:self.overlay atIndex:0];

}

self.overlay.backgroundColor = backgroundColor;

}

2.原因分析:

這個(gè)bug比較奇怪,在ios9及以下的系統(tǒng)中顯示是正常的,但是ios10.0視圖卻顯示不出來。由于創(chuàng)建的視圖未按預(yù)期顯示,

首先,通過Debug->View Debugging->Capture View Hierarchy查看視圖層級(jí)關(guān)系。發(fā)現(xiàn)返回按鈕和titleView是存在的,但是被overlay視圖擋住了,所以未顯示出來。如圖:

存在的視圖,但是被覆蓋了


然后,打印navigationBar的子視圖,發(fā)現(xiàn)有2個(gè)成員:

<_UIBarBackground: 0x7fd5fb76c490; frame = (0 -20; 375 64); userInteractionEnabled = NO; layer = 0x60000022a740>
<_UINavigationBarBackIndicatorView: 0x7fd5fb446160; frame = (8 11.5; 13 21); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer =0x608000435e60> - Back

navigationBar高度是44,上方是statusBar。很明顯_UIBarBackground決定了導(dǎo)航欄的背景色及顯示樣式,因此可以考慮在_UIBarBackground上添加子視圖,用于顯示背景色或圖片。

最后,修復(fù)了該bug。修改后代碼如下:

3.解決方案:

static char overlayKey;

@implementation UINavigationBar (Extension)

- (UIView *)overlay{

return objc_getAssociatedObject(self, &overlayKey);

}

- (void)setOverlay:(UIView *)overlay{

objc_setAssociatedObject(self, &overlayKey, overlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

-(void)ls_setBackgroundColor:(UIColor *)backgroundColor{

if (!self.overlay) {

[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];

//去掉灰色的線。其實(shí)這個(gè)線也是image控制的。設(shè)為空即可

self.shadowImage = [UIImage new];

UIView *barBgView = self.subviews.firstObject;

self.overlay = [[UIView alloc] initWithFrame:barBgView.bounds];

self.overlay.userInteractionEnabled = NO;

self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

[barBgView addSubview:self.overlay];

}

self.overlay.backgroundColor = backgroundColor;

}

@end

可以解決ios10下的導(dǎo)航欄問題。正常的顯示效果為:

返回按鈕和titleView顯示出來了

4.思維發(fā)散:

既然實(shí)現(xiàn)了導(dǎo)航樣單一顏色設(shè)置,如果要顯示為圖片又該如何改呢,是否要新添加一個(gè)UIImageView子視圖?

實(shí)際上不需要,可以通過overlay的圖層的寄宿圖實(shí)現(xiàn),核心代碼如下:

self.overlay.layer.contents = (__bridge id)GET_IMAGE(@"welcome1").CGImage;

在實(shí)踐中,如果你給contents賦的不是CGImage,那么得到的圖層將是空白的。它真正要賦值的類型應(yīng)該是CGImageRef,一個(gè)指向CGImage結(jié)構(gòu)的指針。

另外,可以設(shè)置顯示方式:

self.layerView.layer.contentsGravity = kCAGravityResizeAspect;

contentsGravity的效果等同于UIViewContentModeScaleAspectFit, 同時(shí)它還能在圖層中等比例拉伸以適應(yīng)圖層的邊界。

最后:

如果控件出現(xiàn)一些預(yù)料之外的行為,可以打開XCode的view debugging查看視圖的位置和層級(jí)關(guān)系,找到問題所在。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容