博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UINavigationBar简单解析
阅读量:7221 次
发布时间:2019-06-29

本文共 5027 字,大约阅读时间需要 16 分钟。

额外知识

在开始写UINavigationBar之前,了解几个导航栏中用到的知识,将会更有利于理解。

可单独使用

首先需要明确UINavigationBar是可以脱离UINavigationConroller单独作为控件的。只是UINavigationConroller创建的 navigationBar 的代理UINavigationBarDelegate是 navigationConroller 自身。对于代码或 IB 直接创建的 navigationBar,代理则需要自己指定。

TintColor

相信大家对tintColor这个东西肯定不会陌生,这里就不再累述,只记录一下本人之前的一个疑惑:UILabel为什么不受tintColor的影响?有位大佬在比较详细的讲解了,我就大概记录下自己的理解:

Apple避免在可交互元素上使用边框和渐变,取而代之使用tintColor,那么tintColor的核心思想就是区分元素是否可以响应触摸。显而易见的,UILabel是不可交互元素,即便你设置它的tintColor也不会被绘制。

VisualEffect

系统有三个关于高斯模糊效果的类,父类:UIVisualEffect,两个子类:UIBlurEffectUIVibrancyEffect

UIVisualEffectView就是展示这些效果的视图,里说:

Depending on the desired effect, the effect may affect content layered behind the view or content added to the visual effect view’s contentView.

对于UIVisualEffectView,根据想要的 effect,

  • UIBlurEffect只是简单的给UIVisualEffectView后面的视图添加高斯模糊效果,对于添加到UIVisualEffectViewcontentView中的视图则不会产生模糊效果。

  • UIVibrancyEffect不会给UIVisualEffectView后面的视图产生模糊,只会使添加到contentView中的视图更加生动。

  • 对于UIBlurEffectUIVisualEffectView,若它的contentView中又包含了一个UIVibrancyEffectUIVisualEffectView。则显示效果又有模糊效果,又有生动效果。

lazy var blurContainVibrancyView: UIVisualEffectView = {   let vibrancyEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .light)))   let label = self.creatLabel(withText: "而卒莫消长也")   label.center = vibrancyEffectView.contentView.center   vibrancyEffectView.contentView.addSubview(label)   let blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))   blurEffectView.contentView.addSubview(vibrancyEffectView)   vibrancyEffectView.frame = blurEffectView.frame   vibrancyEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]   return blurEffectView}()复制代码

blurContainVibrancyView

文档指出不要给UIVisualEffectView或者它的父视图设置小于 1 的alpha值,否则 effect 可能显示不正确,或者根本不显示。但是可以设置contentView子视图的alpha(在已经尝试过的实际运用中的时候,设置 UIVisualEffectViewalpha小于 1 时,Xcode 会报警告但是透明和模糊效果都存在。设置它父视图的alpha小于 1 则没有警告但是只有透明效果)。

外观

导航栏样式 barStyle

enum UIBarStyle : Int {        case`default`    case black}复制代码

默认白底黑字,black 样式为黑底白字。且这两种样式都默认半透明(isTranslucent = true)。

barTintColor、tintColor

barTintColor:用来导航栏背景色,不要使用backgroundColor

  • 对于半透明导航栏,设置backgroundColor(蓝色),颜色显示不正确:

半透明设置背景色

  • 对于不透明导航栏,设置backgroundColor,颜色完全不显示:

不透明设置背景色

tintColor:影响 bar 的子视图颜色。

标题文字样式

  • titleTextAttributes:常见的NSAttributedString设置。
  • setTitleVerticalPositionAdjustment(CGFloat, for: UIBarMetrics):标题竖直方向偏移量。

isTranslucent

影响navigationBar的半透明效果,默认为true

  • 对于没有明确设置isTranslucentnavigationBar,如果背景图alpha < 1,则isTranslucent = true。反之为false
  • 对于明确设置isTranslucent = true的,如果背景图为不透明,则会为背景图会被添加小于 1 的系统定义的alpha
  • 对于明确设置isTranslucent = false的,如果背景图alpha < 1,会根据barStylebarTintColor为该图片添加一个相应颜色的不透明背景。

背景图和阴影图

只有在设置过背景图片的情况下,阴影图片才会生效。单独设置阴影图片没有效果。

shadowImage的位置实际上是超出了它的父视图的,设置navigationBar.clipsToBounds = true也可以隐藏。

假设isTranslucent = true

  • 如果没有背景图片,navigationBar的子视图中将会包含一个visualEffectView用来产生模糊效果。

默认视图层级

  • 如果设置了背景图片,navigationBar的子视图中将不会包含visualEffectView,而是直接生成一个半透明的背景图。

设置背景图后的视图层级

代理

导航栏位置 barPosition

public enum UIBarPosition : Int {    case any // 未指明的    case bottom // 指定 bar 在父视图的底部,各种阴影都会被绘制在 bar 顶部    case top // 指定 bar 在父视图的顶部,各种阴影都会被绘制在 bar 底部    case topAttached // 指定 bar 和父视图都在屏幕的顶部,并且 bar 的背景会穿透状态栏}复制代码

barPosition其实是协议UIBarPositioning中定义的属性,UINavigationBar默认遵守了该协议,值为.top

开篇就说到,UINavigationConroller创建的 navigationBar,代理为 navigationConroller 自身。其默认实现为.topAttached

如果自己创建一个 navigationBar 并将其添加到当前控制器视图中,指定代理为当前控制器。并实

UINavigationBarDelegate

func position(for bar: UIBarPositioning) -> UIBarPosition {    return .topAttached}复制代码

可以得到和原生同样的效果(图中系统 iOS 10,高度为自定义,iOS 11 显示效果不一样哟):

自己创建UINavigationBar

拦截返回操作

在项目中时常有点击导航栏返回按钮,弹出确认返回的提示,此时就需要拦截返回事件。

自定义一个NavigationBarShouldPopProtocol将是否可以 pop 的控制权限交给当前控制器,再修改UINavigationController的默认实现,每次都询问topViewController是否可以 pop。且我们可以在shouldPopWhenClickBackButton方法中做一些额外操作(比如返回false,弹出提示框)。

protocol NavigationBarShouldPopProtocol {    func shouldPopWhenClickBackButton() -> Bool}// 点击 navigationBar 的 backButton 是否 pop,默认为 trueextension UIViewController: NavigationBarShouldPopProtocol {    @objc func shouldPopWhenClickBackButton() -> Bool {        return true    }}复制代码
extension UINavigationController: UINavigationBarDelegate {    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {        guard let items = navigationBar.items else {            return false        }                if viewControllers.count < items.count {            return true        }                var shouldPop = true        if let controller = topViewController, controller.responds(to: #selector(UIViewController.shouldPopWhenClickBackButton)) {			// 询问是否可以 pop            shouldPop = controller.shouldPopWhenClickBackButton()        }                if shouldPop {            DispatchQueue.main.async {                self.popViewController(animated: true)            }        } else {            for view in navigationBar.subviews {                if view.alpha > 0 && view.alpha < 1 {                    view.alpha = 1                }            }        }                return false    }}复制代码

转载地址:http://vhiym.baihongyu.com/

你可能感兴趣的文章
BNU OJ 51000 BQG's Random String
查看>>
PAT (Advanced Level) 1044. Shopping in Mars (25)
查看>>
hdu 1531 King
查看>>
***R
查看>>
Linux 源码编译安装mysql
查看>>
取消手机端页面长按图片出现保存或者图片被打开的方法
查看>>
关于图片居中问题
查看>>
并发下的死锁问题
查看>>
Winserver下的Hyper-v “未在远程桌面会话中捕获到鼠标”
查看>>
oracle体系结构基础
查看>>
有关TCP和UDP 粘包 消息保护边界
查看>>
Mono为何能跨平台?聊聊CIL(MSIL)
查看>>
安装scrapy问题:-bash:scrapy:command not found
查看>>
CentOS7 重置root密码
查看>>
博客作业四
查看>>
Scanner 输入---从键盘输入两个数进行相加
查看>>
test
查看>>
说无可说
查看>>
mysql 语句优化
查看>>
SCP 命令参数使用详解(最详细使用指南)
查看>>