导航栏颜色、透明度渐变

前言

在开发过程中,经常会碰到控制器对应的导航栏的背景颜色不一致或者需要让导航栏背景透明的需求。在导航控制器push和pop视图控制器的过程中,直接修改导航栏背景色在视觉上会显得比较突兀。为了给用户更好的使用体验,就需要为导航栏的背景色和透明度变换添加一种合适的动画效果。

UINavigationBar基础

概述

导航栏是UINavigationBar类的实例对象,是一个显示在窗口的顶部并包含用于在屏幕层次结构内进行导航的按钮的栅栏。导航栏最常用于导航控制器中,导航控制器对象创建、显示和管理导航栏,并使用导航控制器管理的视图控制器的相关属性来控制导航栏中显示的内容。

图2-1

使用导航控制器控制导航栏时,需要执行以下步骤:

  • Interface Builder或代码中创建一个导航控制器。
  • 使用UINavigationController对象的navigationBar属性配置导航栏的外观。
  • 通过设置导航控制器堆栈中管理的每个视图控制器的titlenavigationItem属性来控制导航栏的内容。

也可以单独使用导航栏,将导航栏添加到界面中时需要执行以下步骤:

  • 设置自动布局规则来管理界面中导航栏的位置。
  • 创建一个root navigationItem来提供初始标题。
  • 配置委托对象来处理与导航栏的交互。
  • 自定义导航栏的外观。
  • 配置应用程序界面,以便用户在浏览分层屏幕时推入和弹出相关navigationItem

导航栏和导航控制器配合使用

使用导航控制器来管理不同内容屏幕之间的导航时,导航控制器会自动创建导航栏,并在适当的时间推入和弹出navigationItem

在视图控制器出栈和入栈时,导航控制器使用此视图控制器对象的navigationItem属性为其导航栏提供当前需要显示的内容。默认的navigationItem使用视图控制器的标题,但可以通过覆盖UIViewController子类的navigationItem属性来完全控制导航栏内容。

导航控制器会自动将其自身指定为其导航栏对象的委托对象,所以在使用导航控制器时,不要将导航栏的委托对象设置为自定义对象。

要访问与导航控制器关联的导航栏,请使用UINavigationController对象的navigationBar属性。

有关导航控制器的信息,可以参看UINavigationController

添加视图到单独使用的导航栏

在绝大多数场景中,导航栏都是作为导航控制器的一部分使用的。但是有些情况下可能需要单独使用导航栏来实现内容导航方法。单独使用导航栏时,需要为其提供内容。与其他类型的视图不同,不能直接将子视图添加到导航栏,而需要使用navigationItem来指定要显示的按钮或者自定义视图。navigationItemUINavigationItem类的实例对象,其持有用于在导航栏的左侧、右侧和中心指定视图以及用于指定自定义提示字符串的属性,如图2-1所示。

导航栏管理着一个包含UINavigationItem对象的堆栈。堆栈主要用于支持导航控制器,可以使用它来实现我们自己的自定义导航界面。堆栈中最顶端的navigationItem是导航栏当前显示内容所属的navigationItem,使用其pushNavigationItem:animated:方法将新的navigationItem推入到堆栈中,使用popNavigationItemAnimated:方法从堆栈中弹出navigationItem

除了推入和弹出navigationItem之外,还可以直接使用导航栏的items属性或者setItems:animated:方法设置堆栈的内容。可以在应用程序启动时使用此方法将界面恢复到上次关闭应用程序前的状态。下图显示了导航栏是如何管理navigationItem堆栈的:

图2-2

单独使用导航栏时,需要手动为导航栏配置委托对象,委托对象要遵循UINavigationBarDelegate协议。通过实现委托对象的委托方法,委托对象就能接收到导航栏发送的消息。这样就能跟踪何时推入navigationItem到堆栈中或者从堆栈中弹出navigationItem,并根据这些消息来更新应用程序的界面。

有关创建navigationItem的信息,可以参看UINavigationItem。有关委托对象的信息,可以参看UINavigationBarDelegate

自定义导航栏外观

导航栏有两种标准的外观样式:黑色文字配白色背景或者白色文字配黑色背景。使用其barStyle属性来配置外观样式。对导航栏外观样式barStyle属性的更改,会覆盖导航栏从其他与外观有关的属性推断出的显示内容。

导航栏默认是半透明的,可以通过将其translucent属性值设为NO来使导航栏不透明。

可以使用barTintColor属性来设置导航栏背景色,设置此属性会覆盖从barStyle属性推断出的默认颜色。与所有UIView子类一样,可以使用tintColor属性来控制导航栏上控件内容的颜色,包括按钮图片和按钮文字。

titleTextAttributes属性用来指定标题文本外观的,可以分别使用NSFontAttributeNameNSForegroundColorAttributeNameNSShadowAttributeName键为标题文本指定字体、文本颜色、文本阴影颜色和文本阴影偏移量。

使用setTitleVerticalPositionAdjustment:forBarMetrics:方法来调整标题在垂直方向上的位置,UIBarMetrics枚举值定义了导航栏是否紧凑和是否含有提示文本,该方法会根据指定的UIBarMetrics枚举值来调整导航栏的高度。下图显示了具有自定义的背景颜色、标题文本属性和控件内容颜色的导航栏。

图2-3

还可以提供自定义背景图片和阴影图片来完全定制导航栏的外观,调用setBackgroundImage:forBarPosition:barMetrics:方法根据指定的UIBarPosition枚举值和UIBarMetrics枚举值来设置对应导航栏的背景图片。UIBarPosition枚举值定义了导航栏是在窗口底部还是在窗口顶部显示的。

通过配置shadowImage属性值来为导航栏提供自定义阴影图片,但是自定义阴影图片的前提条件是必须要自定义导航栏背景图片。否则,将会使用默认的阴影图片。下图显示了自定义背景图片并自定义阴影图片的导航栏,导航栏的位置值为UIBarPositionTopAttached,高度值为UIBarMetricsDefault

图2-4

导航栏颜色切换、透明度渐变

应用程序在iOS 10以上系统运行时,使用Xcode调试应用程序时,查看半透明导航栏的视图层,其子视图信息如下图所示:

图3-1

如果导航栏不透明,视图层就不会包含UIVisualEffectView视图分支。如果导航栏使用了自定义背景,则会插入一个UIImageView视图到_UIBarBackground视图并位于最底层。另外,在iOS 10以下的系统中运行时,UIVisualEffectView子视图层中的视图会有所改变。

导航栏的外观是由其_UIBarBackground子视图决定的。调用官方提供的方法设置导航栏背景色时,实际调整的是_UIBarBackground子视图的背景颜色,调用官方提供的方法设置导航栏自定义背景图片时,实际上是在_UIBarBackground子视图的最底层添加一个UIImageView视图。

设置导航栏颜色

在视图控制器跳转过程中,UIKit框架会自动对导航栏上的子视图执行一些操作,我们对导航栏上的子视图执行的操作可能会被覆盖掉。所以,为了能够完全控制导航栏的背景色操作,可以在_UIBarBackground子视图最底层手动添加一个子视图,并通过改变这个子视图的背景来控制导航栏的外观背景,这样就不会被官方的操作覆盖掉。

设置导航栏透明度

UIKit框架没有提供方法来直接修改导航栏的透明度,但我们已经知道导航栏的外观由其_UIBarBackground子视图决定。所以,调整_UIBarBackground视图及其子视图的透明度就能改变导航栏的透明度。但在iOS 10以上系统中,在push和pop视图控制器时,UIKit框架会自动重置_UIBarBackground视图的颜色和透明度等属性。这会覆盖掉我们对该视图执行的修改,但我们可以通过方法交换来绕开UIKit框架的这种行为。

为导航栏添加转场动画

对视图控制器执行push或者pop操作时,为了提高用户体验,通常会使用官方提供的转场动画。官方提供的转场动画有交互式和非交互式两种类型。在执行push或者pop操作时,两个视图控制器的对应导航栏背景色不同,直接修改背景色在视觉上会显得很突兀。这时候,就需要给导航栏背景色的切换加上动画效果,让其随着push或者pop转场动画一起执行。

视图控制器的转场动画协调器transitionCoordinator对象提供了animateAlongsideTransition:completion:animateAlongsideTransitionInView:animation:completion:方法来让我们在UIKit框架执行标准的转场动画的同时,对其他视图执行动画。

Demo

示例代码下载地址:https://github.com/Jen668/SJNavigationBarTransition

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容