导航栏的那些事

最近项目里有个需求和导航栏的样式定制有关,深入之后发现之前理解的一些概念有些模糊,刚好趁着这次机会全面整理了一下。

从 iOS7 开始,苹果采用了大量的扁平化和毛玻璃风格,刚升级到 iOS7 之后会发现界面的布局多多少少有一些偏差(当然现在新建的项目没有这方面困扰,不需要经历6到7的适配),适配过程中会发现如下一些属性,

- edgesForExtendedLayout

- translucent

- extendedLayoutIncludesOpaqueBars

- automaticallyAdjustsScrollViewInsets

根据字面意思看上去这些属性很好理解,但是发现他们组合之后会有一些不同的表现,一些奇怪的问题也不知道什么原因导致的。不用担心,接下去我会全面的解析一下这几个属性的含义,保证你再也不怕各种奇怪的导航栏问题啦。

edgesForExtendedLayout + translucent

iOS7 以后,edgesForExtendedLayout 的默认设置是 UIRectEdgeAll,translucent 的默认值是 true。这种组合会使 rootView 的布局从(0,0)开始,即 view 的内容会被导航栏遮挡住,大多数情况下将 edgesForExtendedLayout 修改为 UIRectEdgeNone 就能解决布局被遮挡的问题。将 translucent 设置成 false 也会使 rootView 从导航栏底部开始,但是 translucent = false 时即使将 edgesForExtendedLayout 再改成 UIRectEdgeAll rootView 还是从导航栏底部开始布局。如何可以在导航栏不透明的情况下让 rootView 从(0,0)开始布局呢?苹果也考虑到了这种需求,提供了 extendedLayoutIncludesOpaqueBars 这个属性。

小结:translucent 为 true,rootView 从(0,0)开始布局,修改 edgesForExtendedLayout 属性可以改变布局;translucent 为 false,rootView 从导航栏底部开始布局,修改 edgesForExtendedLayout 属性无法改变布局。

extendedLayoutIncludesOpaqueBars + translucent

前面我们知道了 translucent 为 false 时,修改 edgesForExtendedLayout 也无法使 rootView 从(0,0)开始布局。苹果为此提供了 extendedLayoutIncludesOpaqueBars,字面上理解的意思就是在不透明的导航栏下也全屏显示。

这里多提一点,在 ViewController 的生命周期中有 viewDidLoad,viewWillAppear,viewDidAppear,viewWillDisappear,viewDidDisappear,上述提到的这些属性需要在 viewDidAppear 之前设置好,viewDidAppear 可以认为系统已经根据配置布局好了,在这里展示给用户看。

automaticallyAdjustsScrollViewInsets

automaticallyAdjustsScrollViewInsets 默认值是 true,表示在全屏模式下会自动修改第一个添加到 rootView 的 scrollview 的 contentInset 为(64,0,0,0),这样 scrollview 就不会被导航栏遮挡了。

关于 scrollview 有一个问题比较常见,这里解析一下原因。我们经常会这么使用一个 tableView,

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view.

self.view.backgroundColor = [UIColor greenColor];

self.navigationItem.title = @"Master";

self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds];

_tableView.backgroundColor = [UIColor whiteColor];

_tableView.delegate = self;

_tableView.dataSource = self;

[self.view addSubview:_tableView];

}

这样在默认情况下(translucent = true, edgesForExtendedLayout = UIRectEdgeAll),tableView的显示没有问题。但是当我们将 edgesForExtendedLayout 设置成 UIRectEdgeNone 时,当 tableView 的内容比较多时底部的内容反而显示不下。这就很奇怪了,按照前面的结论,这时候 tableView是从导航栏底部开始布局的,contentInset 也是(0,0,0,0),怎么底部的内容会被遮挡一部分呢?原因在于 self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; 初始化时 rootView 的 frame 还是(0,0,screenWidth,screenHeight),只需要在 viewWillLayoutSubviews 中重新修改一下 tableview 的 frame 即可,

- (void)viewWillLayoutSubviews

{

[super viewWillLayoutSubviews];

_tableView.frame = self.view.bounds;

}

UINavigationBar 修改背景色

UINavigationBar 是 UIView 的子类,首先想到的是修改背景色,

self.navigationController.navigationBar.backgroundColor = [UIColor greenColor];

发现这并不是我们想要的效果,为什么绿色变淡了呢?通过 Xcode 的 ViewDebugging 我们可以看到 UINavigationBar 内部还有一些子视图,这些子视图的背景色会遮挡住我们设置的颜色。

查看 UINavigationBar 的接口我们发现 setBackgroundImage,设置

[self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[UIColor greenColor] size:CGSizeMake(1, 1)] forBarMetrics:UIBarMetricsDefault];

结果如下

小结:设置 UINavigationBar 的 backgroundImage 可以修改导航栏的背景色。

translucent 和 setBackgroundImage

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

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

/*

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

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

至此,我们了解了苹果是如何使用这几个属性的,针对 iOS7 以上,这里做一下总结:

  1. iOS7 以后 translucent 默认为 true,rootView 从(0,0)开始布局,修改 edgesForExtendedLayout 属性可以改变布局;
  2. translucent 为 false,rootView 从导航栏底部开始布局,修改 edgesForExtendedLayout 属性无法改变布局,可以通过设置 extendedLayoutIncludesOpaqueBars 从(0,0)开始布局;
  3. automaticallyAdjustsScrollViewInsets 默认值是 true,表示在全屏模式下会自动修改第一个添加到 rootView 的 scrollview 的 contentInset 为(64,0,0,0),用来纠正scrollview在全屏模式下的显示;
  4. 设置 UINavigationBar 的背景图片可以改变导航栏背景色,如果背景图片包含 alpha 的色值,系统会默认将 translucent 设置为 true,没有包含 alpha 色值会将 translucent 设置为 false。但这是针对没有手动设置 translucent 值的情况,如果我们手动设置了 translucent,那么系统就不会根据背景图片的 alpha 来修改 translucent。
时间: 2024-10-12 20:16:01

导航栏的那些事的相关文章

系统适配杂谈之一:ios7和ios8关于导航栏的那些事

ios7之前的版本中UIViewController中的view在显示后会自动调整为去掉导航栏的高度的,控件会自动在导航栏以下摆放. 在iOS7中UIViewController的wantsFullScreenLayout属性被舍弃了,所有的UIViewController创建后默认就是full Screen的,因此如果带导航栏的应用界面中的部分控件会被导航栏覆盖掉. 解决方案:可以使用ios7种UIViewController新增的属性extendLayoutIncludesOpaqueBar

导航栏对于UIScrollview以及子类所做的一些事

目的: - 了解导航栏对于UIScrollview以及子类所做的一些事 步骤: - 查看下图,我这边是一个导航栏的主控制器视图上面加了两个子控制器,可以清晰的看到左边一个tableView被没有被导航栏挡住,而后面一个被会挡住. - 而当我在一开始先添加一个其它的控件时,也就是未添加子控制器时第一个也会被挡住,这是什么原因呢?这是因为下面这个属性,默认为YES. // 不会自动去调整uiscrollView的contentInset属性 self.automaticallyAdjustsScro

Android仿小米商城底部导航栏之二(BottomNavigationBar、ViewPager和Fragment的联动使用)

简介 在前文<Android仿小米商城底部导航栏(基于BottomNavigationBar)>我们使用BottomNavigationBar控件模仿实现了小米商城底部导航栏效果.接下来更进一步的,我们将通过BottomNavigationBar控件和ViewPager空间的联动使用来实现主界面的滑动导航. 导航是移动应用最重要的方面之一,对用户体验是良好还是糟糕起着至关重要的作用.好的导航可以让一款应用更加易用并且让用户快速上手.相反,糟糕的应用导航很容易让人讨厌,并遭到用户的抛弃.为了打造

页面刷新跳转后,导航栏高亮显示跳转前的点击位置

需求:比如有一个二级或三四级的菜单栏,页面不跳转时实现高亮显示是很容易的,网上有很多这样的素材.但是页面一跳转,新页面可就记不住你在上一个页面点击的位置了,也就不可能高亮显示.并且很多时候,跳转后的页面菜单栏是后台动态生成的,也就是菜单栏栏目不固定,那么就不可能给菜单栏高亮效果写死.不知道这个事利用前后台交互去做会不会容易点,但是现在是要用纯前台实现. 实现原理一:这时候必须找个地方给它把点击的位置存起来,等页面跳转后,从那个地方把标记取出来,再给导航相应的位置做高亮处理就好了. 方法1:利用

【翻译】移动端友好的响应式导航栏教程

以下是译文: 今天我来教大家设计一个色彩绚丽且移动端友好的响应式导航栏.这个导航栏的灵感源自一款叫做"无主之地(Borderlands)"游戏中的一个叫做Maliwan武器生产商商标所采用的颜色集.导航栏会自动根据浏览器窗口的大小调整布局格式:在PC宽度下呈现为一行按钮,在平板宽度下呈现为三行按钮,而在移动端则变成了一个菜单栏按钮连接,点击可以显示和隐藏整个导航栏.为了使这个导航栏做到真正地移动端友好,我们将采用图标字体来作为导航栏图表,这样的话,当界面放大缩小的时候,图标也会自动调整

【原创+译文】官方文档中声明的如何创建抽屉导航栏(Navigation Drawer)

如需转载请注明出处:http://www.cnblogs.com/ghylzwsb/p/5831759.html 创建一个抽屉导航栏 抽屉式导航栏是显示在屏幕的左边缘,它是应用程序的主导航选项面板.它大部分时间是处于隐藏状态的,但是当用户从屏幕的左边缘挥动手指时它就会显示出来,而在应用程序的顶层,用户触摸操作栏上的应用程序图标也可以将其显示出来. 本课程介绍在可用的API 支持库下如何实现导航抽屉DrawerLayout. 首先我们可以看一下最终的效果图: 1.创建一个抽屉布局文件(Drawer

android ViewPager左右滑动实现导航栏的背景随页面滑动而滑动

实现viewPager和导航栏进行结合的效果图:废话不说直接上图看效果:      随着左右的滑动背景的黄色也随着滑动,代码如下: 布局  weibo_2.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width=

&lt;iOS 导航栏&gt;第一节:导航栏透明方法实现代码

说下导航栏的透明方法: 很多应用需要导航栏随着向上滑动,逐渐从透明变成不透明,很炫酷,大部分应用都在使用导航栏渐变效果,现附上代码然后直接将实现,一会讲下如何来实现,这一部分直接上代码. 先附上代码: 方法声明: #import <UIKit/UIKit.h> @interface IDSNavBarView : UIView - (instancetype)initWithFrame:(CGRect)frame titleImg:(UIImage *)aTitleImg; - (UILabe

JS学习笔记(一): 使用原生JS 实现导航栏下多级分类弹出效果

在给静态页面静添加交互效果时遇到的问题 : 鼠标划入二级菜单时 一级菜单样 ":hover" 式无法保持 情景如下: 解决思路: 利用二级菜单的onmouseover/out事件 重新构建一级菜单 ".hover" 样式类 代码如下: CSS部分: 在原来的目标:hover样式中 增加 .hover状态 li.app_jd a:hover,li.app_jd a.hover{ background-position: -126px -397px; } li.serv