0%

iOS-NavigationBar的backgroundColor

在代码中发现设置navigationBar的背景颜色都是将一个颜色绘制为 UIImage 然后 通过 setBackgroundImage()进行赋值,而没有使用常见的 backgroundColor。

尝试直接给 navigationBar 直接设置 backgroundColor 发现并没有正常工作,只有在 UINavigationBarAppearance().backgroundColor 上赋值才会有用,所以查找资料了解了一下navigationBar的背景颜色

backgroundColor

直接添加

1
backgroundColor = .green

会被 navigationBar 的 isTranslucent 属性所影响:

isTranslucent = false

IMG_C56A633B2AED-1

isTranslucent = true

IMG_0123

也就是说 他是真正的背景颜色 navigationBar的颜色设置不来源于继承自UIView的 backgroundColor

附:在iOS15中 navigationBar 默认为全透明 所以此时的表现是这样:

IMG_532CFEA85A81-1

barTintColor

barTintColor 才是真正设置 navigationBar 的 backgroundColor 的方法但是直接使用

1
barTintColor = .orange

的颜色并不是真正的 .orange 上面蒙了一层白色

IMG_0125

查找官方文档后发现 isTranslucent属性默认为true 那如果将 isTranslucent 设为 false呢

IMG_0126

附:tintColor是应用于导航项和按钮项的色调颜色

A navigation bar diagram that depicts the fonts, color, and layout of a navigation bar, including the tint color, title text atributes, bar tint color, and the title vertical position.

那我们如果既想使用半透明 又想要纯正的颜色呢 那就需要设置backgroundImage了:

backgroundImage

直接设置 backgroundImage 即可得到我们想要的效果(imge()为给UIColor添加的extension)

1
setBackgroundImage(UIColor.yellow.image(), for: .default)

IMG_0127

但是如果我们设置一个半透明图片

1
setBackgroundImage(UIColor.yellow.withAlphaComponent(0.5).image(), for: .default)

则出现了和之前一样的问题 translucent 为 true 时 影响到了原来的布局。

IMG_0CA250DF94E3-1

translucent 和 setBackgroundImage

前面提到我们可以通过修改背景图片来修改导航栏的背景色,设置了背景图片后在有些页面我们会遇到一些奇怪的问题,发现原来布局正常的页面显示不对了,会多出一部分空白或者被导航栏遮挡住了。

通过打印出 translucent 的值我们发现设置了纯色的背景图后原来半透明的导航栏变成了不透明的,结合前面提到的 translucent 对布局起点的影响,如果页面是按照半透明情况,即 rootView 从(0,0)开始布局来设置子视图的 frame,那么设置了纯色背景图后 translucent 变成了 false,此时 rootview 从 navigationBar 下面开始布局 。为什么设置背景图片会影响 translucent 呢,通过查看文档发现了如下说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
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.
*/
@property(nonatomic,assign,getter=isTranslucent) BOOL translucent NS_AVAILABLE_IOS(3_0) UI_APPEARANCE_SELECTOR; // Default is NO on iOS 6 and earlier. Always YES if barStyle is set to UIBarStyleBlackTranslucent

也就是说背景图片如果包含 alpha 的色值,系统会默认将 translucent 设置为 true,没有包含 alpha 色值会将 translucent 设置为 false。这下真相大白了,原来我们前面设置了纯绿色的背景图片,是不包含 alpha 色值的,即系统默认将 translucent 设置成了 false。但这是针对没有手动设置 translucent 值的情况,如果我们手动设置了 translucent,那么系统就不会根据背景图片的 alpha 来修改 translucent

至此,我们了解了苹果是如何使用这几个属性的:

  1. translucent 默认为 true,rootView 从(0,0)开始布局
  2. translucent 设置为 false,rootView 从导航栏底部开始布局
  3. automaticallyAdjustsScrollViewInsets 默认值是 true,用来纠正scrollview在全屏模式下的显示;
  4. 设置 UINavigationBar 的背景图片可以改变导航栏背景色,如果背景图片包含 alpha 的色值,系统会默认将 translucent 设置为 true,没有包含 alpha 色值会将 translucent 设置为 false。但这是针对没有手动设置 translucent 值的情况,如果我们手动设置了 translucent,那么系统就不会根据背景图片的 alpha 来修改 translucent

上面是在iOS13以前的 Legacy Customizations 在 iOS13 苹果提出了新的 UINavigationBarAppearance来配置navigationBar的 standardAppearance, compactAppearance, scrollEdgeAppearance 三种状态。

UINavigationBarAppearance 继承自 UIBarAppearance ,在这里我们可以自由的定义backgroundColor 等等各种属性。

苹果官网的介绍:https://developer.apple.com/documentation/uikit/uinavigationbar

Customize the Appearance of a Navigation Bar

Navigation bars have two standard appearance styles: white with dark text or black with light text. Use the barStyle property to select the style. Any changes you make to other navigation bar appearance properties override those inferred from the bar style.

Navigation bars are translucent by default; that is, their background color is semitransparent. You can make the navigation bar opaque by setting the isTranslucent property to false.

You can specify a custom tint color for a navigation bar background using the barTintColor property. Setting this property overrides the default color inferred from the bar style. As with all UIView subclasses, you can control the color of the interactive elements within navigation bars, including button images and titles, using the tintColor property.

The titleTextAttributes property specifies the attributes for displaying the bar’s title text. You can specify the font, text color, text shadow color, and text shadow offset for the title in the text attributes dictionary using the font, foregroundColor, and shadow keys, respectively. For more information about string-formatting attributes, see Character Attributes.

Use the setTitleVerticalPositionAdjustment(_:for:) method to adjust the vertical position of the title. This method allows you to specify the adjustment dependent on the bar height, which is represented by the UIBarMetrics enum. The following figure shows a navigation bar with custom tint color, title text attributes, and bar tint color.

A navigation bar diagram that depicts the fonts, color, and layout of a navigation bar, including the tint color, title text atributes, bar tint color, and the title vertical position.

To allow complete customization over the appearance of navigation bars, you can additionally provide custom background and shadow images. To provide a custom background image, use the setBackgroundImage(_:for:barMetrics:) method, providing a UIImage object for the appropriate bar position and metrics values. Use a UIBarPosition value for the bar position argument to specify whether to use the supplied image at the bottom or the top of the window, and if it appears at the top, whether to extend it upward under the status bar. Similarly, you can specify that the image should be used for either compact or default bar metrics, with or without a prompt, by providing a UIBarMetrics value to the bar metrics argument.

To add a shadow, provide a resizable UIImage to the shadowImage property. To use the custom shadow image, you need to have specified a custom background image. The following figure shows a navigation bar with a custom background image, supplied using setBackgroundImage(_:for:barMetrics:) with a bar position value of UIBarPosition.topAttached and a bar metrics value of UIBarMetrics.default. A custom image has also been provided to the shadowImage property.

A screenshot of a navigation bar with the location of a background image and a shadow image labeled.

To see examples of customizing a navigation bar, see Customizing Your App’s Navigation Bar.