UINavigationBar 的详解 (基于 API)

UINavigationBar是什么?

一个支持分层内容导航的视觉控件,最常用于导航控制器。

基本组成

UINavigationBar对象是一个bar,通常显示在窗口的顶部,包含用于在屏幕层次结构中导航的按钮。 主要组件:左( 返回)按钮,中心标题和可选的右按钮。(下图所示)

UINavigationBar外观的定制

UINavigationBar的外观包括背景颜色,背景图片,文字颜色,按钮文字颜色等等,你所看到的一些UINavigationBar上的一些元素都可以是他的外观,如何更改他们呢? 个人认为首先要了解UINavigationBar的一些关乎外观的属性。下面看一段UINavigationBar的源码

open class UINavigationBar : UIView, NSCoding, UIBarPositioning {

    // UINavigationBar的风格,是一个枚举,下边会给出源码,并作出解释。
    open var barStyle: UIBarStyle
    
    // 半透明的属性。这个属性关乎着UINavigationBar是不是有半透明的毛玻璃效果。默认是 ture.我们常常会看到UINavigationBar是半透明的。改为 false,就不再透明。
    @available(iOS 3.0, *)
    open var isTranslucent: Bool 

  // 这个属性在 iOS7之后并不会改变UINavigationBar的背景颜色,改变的是UINavigationBar上各个 item 的文字、图形的颜色
    open var tintColor: UIColor!
// 这个属性是真正改变UINavigationBar北京颜色的属性,默认是 nil
    @available(iOS 7.0, *)
    open var barTintColor: UIColor? 

   // 设置给定栏位置和一组指标的背景图像。
    @available(iOS 7.0, *)
    open func setBackgroundImage(_ backgroundImage: UIImage?, for barPosition: UIBarPosition, barMetrics: UIBarMetrics)

// 返回给定条形位置和指标集的背景图像。
    @available(iOS 7.0, *)
    open func backgroundImage(for barPosition: UIBarPosition, barMetrics: UIBarMetrics) -> UIImage?

    // 设置给定条指标的背景图像。
    @available(iOS 5.0, *)
    open func setBackgroundImage(_ backgroundImage: UIImage?, for barMetrics: UIBarMetrics)

// 返回给定条指标的背景图像。
    @available(iOS 5.0, *)
    open func backgroundImage(for barMetrics: UIBarMetrics) -> UIImage?

    
  // 默认值为nil对应于默认阴影图像。当此属性非nil时,表示要显示自定义的阴影图像。如果要自定义阴影图像显示出来,还必须使用set​Background​Image(_:​for:​)方法设置自定义背景图像,不然shadowImage不会显示。如果使用的是默认的背景图像,shadowImage只会使用默认的阴影图像,而不显示设置的属性的值。
  // 表示用作导航栏下方阴影的图像。此图像水平拉伸以匹配条的宽度,常见的就是导航条下边的那条黑线。
    @available(iOS 6.0, *)
    open var shadowImage: UIImage?

  // 可以指定字体,文本颜色,文字阴影颜色,用来设置 title 的字体样式。可以看出属性值是一个字典,字典的键值要从 NSAttributedString.h 文件中去选择。
    @available(iOS 5.0, *)
    open var titleTextAttributes: [String : Any]?

  // 设置标题的垂直位置调整给定的条形度量。
    @available(iOS 5.0, *)
    open func setTitleVerticalPositionAdjustment(_ adjustment: CGFloat, for barMetrics: UIBarMetrics)

   //返回给定条形指标的标题垂直位置调整。
    @available(iOS 5.0, *)
    open func titleVerticalPositionAdjustment(for barMetrics: UIBarMetrics) -> CGFloat

   //back按钮旁边显示的图像。指定出现在back按钮前端的图像
    @available(iOS 7.0, *)
    open var backIndicatorImage: UIImage?
   // 图像在推送和弹出转换期间用作内容的遮罩。这用于在动画转换期间控制“后退”按钮的外观,因此必须与“返回图像”属性配合使用。 这两个属性必须同时设置。back 图像才会生效
    @available(iOS 7.0, *)
    open var backIndicatorTransitionMaskImage: UIImage?
}

复制代码

关于barStyle的枚举值源码:

public enum UIBarStyle : Int {

    case `default`

    case black

    public static var blackOpaque: UIBarStyle { get } // Deprecated. Use UIBarStyleBlack

//  这个值一般的不建议使用。而是建议将barStyle设置为 black,然后再设置translucent 为 true 来实现
    case blackTranslucent 
}
复制代码

UINavigationBar 的层次结构

了解了一些可以改变UINavigationBar外观的属性,这些属性是怎样实现改变UINavigationBar的外观的呢?我们需要来看一下构成UINavigationBar整个视图的结构。

可以看到整个 UINavigationBar 是有层次结构的,包含有 UIIMageView,UIVisualEffectView,UILabel 等基本视图。其中UIVisualEffectView就是来完成毛玻璃的效果的。那条底部的黑线其实就是一个 UIImageView。

利用属性改变 UINavigationBar 外观

    override func viewDidLoad() {
        super.viewDidLoad()

		view.backgroundColor = UIColor.white

		// 导航栏的 title
		self.navigationItem.title = "Title"
		// 导航栏右侧添加了一个 item
		self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(ss))
		
		// tintColor  你会看到导航栏上左右两边的 item 的颜色改变了,并没有改变导航栏的背景颜色
	    self.navigationController?.navigationBar.tintColor = UIColor.brown
		
		// 改变 barStyle ,默认是导航栏背景颜色是白色,导航栏 title 的颜色是黑色,状态栏的字颜色也是黑色。 更改为 black 之后导航栏背景颜色更改为黑色,导航栏 title 变为白色,状态栏字颜色也为白色。
		self.navigationController?.navigationBar.barStyle = .black
		
		// barTintColor 改变导航栏的背景颜色。即使 barStyle为 black,依旧可以改他的背景颜色
		self.navigationController?.navigationBar.barTintColor = UIColor.cyan
		
		// titleTextAttributes 改变导航栏 title 的文字属性,包括大小,颜色等
		self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.yellow, NSFontAttributeName: UIFont.systemFont(ofSize: 24)]
		
		// 设置导航栏的背景图片 很显然这个时候背景颜色看不到了 
		let image = UIImage(named: "公桩_选中")
		self.navigationController?.navigationBar.setBackgroundImage(image, for: .top, barMetrics: .default)
		
		// 设置shadowImage 这个时候导航栏下边的那条黑线就消失了,成为我们设置的图片。这也为我们去除导航条底部的那条黑线提供了一个方法
		let image1 = UIImage(named: "首页-选中")
		self.navigationController?.navigationBar.shadowImage = image1
		
		// 半透明的属性我们暂且注释掉,后边有更好的展示使用效果
		//self.navigationController?.navigationBar.isTranslucent = false

    }
复制代码

去除导航栏下边的那条黑线

   override func viewDidLoad() {
        super.viewDidLoad()
		
		view.backgroundColor = UIColor.yellow
		// 去除黑线只需要设置背景图片 和  shadowImage 两个 就可以去掉,就是下边两行
		self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
		self.navigationController?.navigationBar.shadowImage = UIImage()
    }
复制代码

解决导航条背景色和 View中有相同颜色的 View 有色差的问题

问题的基本变现是下边这个样子的,你会发现导航栏颜色和 button 颜色不一样!(这张图片有点打脸,竟然看不出来有色差,同仁们可以自己去设置看一下,请自行脑补吧)

在之前我们看过这个UINavigationBar 的层次结构,在导航栏上是有一个触发毛玻璃效果的 view。会不会是他的效果呢?我们设置 isTranslucent 属性来看一下效果。

// 添加到上边的代码 结果如下图
	self.navigationController?.navigationBar.isTranslucent = false
复制代码

添加以上代码结果是什么样子呢?

出现了新的问题,button 的位置发生变化,下边讲解原因以及办法。

解决 isTranslucent = false 导致的约束(位置)变化的问题

此时来看一下这个界面的视图层次结构。

这里会发现选中的那个视图比别的高度变小了,原因就是这个。下面我们就给出解决的代码和解释:

    override func viewDidLoad() {
        super.viewDidLoad()
		view.backgroundColor = UIColor.white
	//	self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
//		self.navigationController?.navigationBar.shadowImage = UIImage()
		self.navigationController?.navigationBar.barTintColor = UIColor.red
		
		// isTranslucent = false  坐标系发生变化(0,0)点下移到导航栏左下点,也就是之前的 (0,64)是现在的(0,0)点,整个 view 的高度也缩小了64
		self.navigationController?.navigationBar.isTranslucent = false
       这是之前的设置,注意看 y 坐标
       //let but1 = UIButton(frame: CGRect(x: 0, y: 64, width: self.view.frame.width	, height: 100))
	
		// 现在把 button 的 y 坐标变为 0 ,就可以解决约束变化的问题了
		let but1 = UIButton(frame: CGRect(x: 0, y: 0, width: self.view.frame.width	, height: 100))
		but1.setTitle("这是一个 BUTTON", for: .normal)
		but1.addTarget(self, action: #selector(click1), for: .touchUpInside)
		but1.backgroundColor = UIColor.red
		view.addSubview(but1)
    }
复制代码

效果怎么样呢?

isTranslucent = false ,很明显解决了颜色偏差的问题,以及位置变化的问题。 最终结果:

此时有人觉得黑线的存在会影响美感,只要用上边去除黑线的方法,去除就可以了。将上边的代码中去除黑线的注释去掉就是完成的代码了。

还有的人会遇到下面的问题。

去除黑线 ,给导航栏添加背景颜色barTintColor 不显示。

当然你可以设置一个同样颜色的背景图片来达到效果。 那么到底是什么导致去除了黑线之后,设置 barTintColor 为背景颜色之后, 不显示背景颜色呢?,关键点在于isTranslucent为 false 。 同时要注意上边的坐标系变化问题。

    override func viewDidLoad() {
        super.viewDidLoad()
		
		view.backgroundColor = UIColor.white
      // 去除黑线的两行代码
		self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
		self.navigationController?.navigationBar.shadowImage = UIImage()
      //  添加背景颜色
		self.navigationController?.navigationBar.barTintColor = UIColor.red
		将背景颜色显示出来
		self.navigationController?.navigationBar.isTranslucent = false

    }
复制代码

当然实现的方法有很多,大家都可以尽情的去尝试,包括自定义一个导航栏。

以上内容仅仅是改变背景颜色会涉及到的一些小知识,到此上边所介绍的一些属性基本就剩下导航栏的返回按钮没有设置了吧。

自定义返回箭头

自定义返回箭头自然就要用到 backIndicatorImage 和 backIndicatorTransitionMaskImage 这两个属性了。前边已经说过这两个属性必须同时使用,返回箭头才能设置成功。 具体实现如下:

	func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
		
		UINavigationBar.appearance().backIndicatorImage = UIImage(named: "arrow_44")
		UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "arrow_44")

		return true
	}
复制代码

建议写到 AppDelegate中的 didFinishLaunchingWithOptions方法中,并使用 UIAppearance 来改变整个项目中的所有导航栏的返回按钮的外观。 设置返回图片你可能会遇到的坑: 这是我设置图片的时候遇到的一些小坑,在这里也提出来 避免有同仁掉坑,同时也有助于大家爬坑! 第一个坑:你可能会发现自己给的箭头很大。 第二个坑:你发现自己设置的箭头第一次出现的时候回移动一下 这些凡是图片感觉不太对的问题都是因为图片的裁剪的问题,你应该让 UI设计师给你标准大小的图片。什么是标准大小的图片呢? UI设计师应该知道的,它的大小和 Tabbar 的图标的大小是一样的。 如果还不知道,没关系我告诉你尺寸:一倍图 21* 21 二倍图 4242 三倍图: 63 63

到此使用 UINavigationBar的相关属性来改变外观的方法基本结束了,他的属性的理解也有有讲解,必须再提一句的是: 如果你想改变整个项目所有的导航栏的外观请使用 UIAppearance 方法。 如果你想要只改变某一个导航栏的外观就用以上例子中的 self.navigationController?.navigationBar 来调用每个属性。

快餐:

基于有的同仁急于解决问题并不想啰里啰嗦看这么多,下面会给出实现的全部代码,一下代码都是改变整个项目所有导航栏外观的实现方法。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
		
		// tintColor  你会看到导航栏上左右两边的 item 的颜色改变了,并没有改变导航栏的背景颜色
		UINavigationBar.appearance().tintColor = UIColor.brown
		
		// 改变 barStyle
		UINavigationBar.appearance().barStyle = .black
		
		// barTintColor 改变导航栏的背景颜色
		UINavigationBar.appearance().barTintColor = UIColor.cyan
		
		// titleTextAttributes 改变导航栏 title 的文字属性,包括大小,颜色等
		UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.yellow, NSFontAttributeName: UIFont.systemFont(ofSize: 24)]
		
		// 设置导航栏的背景图片 很显然这个时候背景颜色看不到了
		//let image = UIImage(named: "navBackground")
		//UINavigationBar.appearance().setBackgroundImage(image, for: .top, barMetrics: .default)
		
		// 设置shadowImage 这个时候导航栏下边的那条黑线就消失了,成为我们设置的图片。这也为我们去除导航条底部的那条黑线提供了一个方法
		//let image1 = UIImage(named: "navBackground")
		//UINavigationBar.appearance().shadowImage = image1
		
		// 去除导航栏下边的黑线
		UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
		UINavigationBar.appearance().shadowImage = UIImage()
		
		
	
		// isTranslucent = false  坐标系发生变化(0,0)点下移到导航栏左下点,也就是之前的 (0,64)是现在的(0,0)点,整个 view 的高度也缩小了64
	
		// 半透明的属性我们暂且注释掉, 添加了去除黑线的方法后,会发现背景颜色就被有了, 放开这个注释背景颜色就会出现,不过需要注意他的坐标系的变化
		
		//UINavigationBar.appearance().isTranslucent = false
		
     // 自定义返回按钮
		UINavigationBar.appearance().backIndicatorImage = UIImage(named: "arrow_44")
		UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "arrow_44")
	
		return true
	}

复制代码

以上就是一些基本的设置了,还是建议把上边的详细内容看一些 能避免掉坑。

欢迎拍砖探讨!

本篇内容所涉及到的都是在基本属性上边的颜色等外观的改变,还不涉及到添加导航栏的navigationItem,下一篇我们会具体来探讨的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值