今天用Xcode8.2 新建一個Demo,底部一個Tabbar,上面一個導航欄,之前的項目是老板版建立的,將之前的代碼拉進來,瞬間方了,腫么回事!看到下效果圖
A)[UINavigationBar appearance].backgroundColor = RColor; 
B)修改后的效果 
可以看出顏色的不同,后者顏色深些,這才是該顏色值,我們利用Xcode–Debug–View Debugging–Caputre View Hierarchy,看視圖的層級關系 
A) 
原來NavagationBar前有好幾層的view,是他們遮擋了真正的顏色,打印看NavigationBar的subviews
NSLog(@"navigationbar subviews recursive descr
最前面的一層 顏色有透明度
B) 
此處的解決方法是,在程序運行時,插入一個view在NavigationBar中,在B的層級圖中可以UIView。
貼上代碼
- (UIView *)overlay{ return objc_getAssociatedObject(self, &YCFOverlayKey);}- (void)setOverlay:(UIView *)overlay{ objc_setAssociatedObject(self, &YCFOverlayKey, overlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (void)YCFSetBackgroundColor:(UIColor *)backgroundColor{ if (!self.overlay) { [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault]; UIView *backgroundView = [self KPGetBackgroundView]; self.overlay = [[UIView alloc] initWithFrame:backgroundView.bounds]; self.overlay.userInteractionEnabled = NO; self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; [backgroundView insertSubview:self.overlay atIndex:0]; } self.overlay.backgroundColor = backgroundColor;}- (void)YCFSetBackgroundImage:(UIImage *)imageName{ if (!self.overlay) { [self setBackgroundImage:imageName forBarMetrics:UIBarMetricsDefault]; UIView *backgroundView = [self KPGetBackgroundView]; self.overlay = [[UIView alloc] initWithFrame:backgroundView.bounds]; self.overlay.userInteractionEnabled = NO; self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; [backgroundView insertSubview:self.overlay atIndex:0]; } self.overlay.backgroundColor = [UIColor clearColor];}- (UIView*)KPGetBackgroundView{ //iOS10之前為 _UINavigationBarBackground, iOS10為 _UIBarBackground //_UINavigationBarBackground實際為UIImageView子類,而_UIBarBackground是UIView子類 //之前setBackgroundImage直接賦值給_UINavigationBarBackground,現在則是設置后為_UIBarBackground增加一個UIImageView子控件方式去呈現圖片 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) { UIView *_UIBackground; NSString *targetName = @"_UIBarBackground"; Class _UIBarBackgroundClass = NSClassFromString(targetName); for (UIView *subview in self.subviews) { if ([subview isKindOfClass:_UIBarBackgroundClass.class]) { _UIBackground = subview; break; } } return _UIBackground; } else { UIView *_UINavigationBarBackground; NSString *targetName = @"_UINavigationBarBackground"; Class _UINavigationBarBackgroundClass = NSClassFromString(targetName); for (UIView *subview in self.subviews) { if ([subview isKindOfClass:_UINavigationBarBackgroundClass.class]) { _UINavigationBarBackground = subview; break; } } return _UINavigationBarBackground; }}#PRagma mark - shadow view- (void)KPHideShadowImageOrNot:(BOOL)bHidden{ UIView *bgView = [self KPGetBackgroundView]; //shadowImage應該是只占一個像素,即1.0/scale for (UIView *subview in bgView.subviews) { if (CGRectGetHeight(subview.bounds) <= 1.0) { subview.hidden = bHidden; } }}參考鏈接1 參考鏈接2
上面兩種方法都是可行。 上面是因為設置translucent是YES,7.0以后,默認值是YES,以前都是NO,事實上都是這個屬性在搞鬼
New behavior on iOS 7. Default is YES. You may force an opaque background by setting the property to NO. If the navigation bar has a custom background image, the default is inferred from the alpha values of the image—YES if it has any pixel with alpha < 1.0 If you send setTranslucent:YES to a bar with an opaque custom background image it will apply a system opacity less than 1.0 to the image. If you send setTranslucent:NO to a bar with a translucent custom background image it will provide an opaque background for the image using the bar's barTintColor if defined, or black for UIBarStyleBlack or white for UIBarStyleDefault if barTintColor is nil.YES(半透明),NO(不透明) 如果自定義的圖像alpha<1.0,translucent=NO,則導航欄會為圖像提供不透明背景, 如果自定義的圖像alpha<1.0,translucent=YES,則導航欄會為圖像提供透明背景
根據測試,其實設置backgroundcolor跟設置backgroundImage是一樣的效果
若是在最開始就設置了translucent=NO,那么后續代碼也就不需要,也不會出現半透明的導航欄。正好這個機會也好好了解了NavigationBar的視圖層次,不然也不曉得它是如何實現的。
有個疑問,在運行時給NavigationBar插入一個UIView之后,原先的那個UIVisualEffectView不見了,這是怎么回事呢?知道的請告知。謝謝!
如果有什么不對的地方也請指正,謝謝!
新聞熱點
疑難解答