iOS10.0適配-導航欄問題

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

1.復現(xiàn):

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

返回按鈕及titleView都不顯示

項目中使用了UINavigationBar + Extension擴展,通過對UINavigationBar添加子視圖的方式設置背景圖。

使用的源碼如下:

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

if (!self.overlay) {

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

//導航欄下面有一條1像素高的灰色的線,這是一張圖片,可能過設置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.原因分析:

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

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

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


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

<_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決定了導航欄的背景色及顯示樣式,因此可以考慮在_UIBarBackground上添加子視圖,用于顯示背景色或圖片。

最后,修復了該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];

//去掉灰色的線。其實這個線也是image控制的。設為空即可

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下的導航欄問題。正常的顯示效果為:

返回按鈕和titleView顯示出來了

4.思維發(fā)散:

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

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

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

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

另外,可以設置顯示方式:

self.layerView.layer.contentsGravity = kCAGravityResizeAspect;

contentsGravity的效果等同于UIViewContentModeScaleAspectFit, 同時它還能在圖層中等比例拉伸以適應圖層的邊界。

最后:

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

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

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