IOS开发入门(11)-导航控制器(1)

IOS开发入门(11)-导航控制器I:层级结构和标签

前言:(直接从书上抄的)

  大多数应用程序是由主视图导出多个屏幕,并且通常情况下实现屏幕切换的方法还不止一种。我们需要一种方式来实现用户在应用程序内来回移动,以及让用户知道他们所在的具体部分提供的功能之间的切换。

  在iPhone设备上,大多数使用导航控制器的应用程序可以分为两种。一种使用简单的主视图来导航一系列展示或多或少、渐进的细节场景。通讯录、笔记和设置就是不错的示例。其他的,比如闹钟和音乐,则有许多主视图,各自拥有不同的功能,设置拥有自己的内容层次。

  iOS提供控制器来管理每种内容之间的导航。UINavigationController用于在各种层次结构的信息之间上下移动,而UITabBarController则处理多个主视图之间的切换。

  本节就是介绍这两种方法怎么使用。

1 导航控制器

  我们来看一下设置是长啥样的吧,下图展示的是setting方法应用程序中的某个局部的层级结构

这里写图片描述

  在iPhone上,这是常见的组织内容的方式。该方式优雅地解决了如何在狭小空间内显示大量内容的问题。setting允许修改iPhone和setting内部各种应用程序的数以百计的设置选项。采用层次结构的方式来“折叠”内容,能够很好地应用两种屏幕尺寸,以及很好地复合人们通常善于分类和分组的情况。

  那些拥有带层次结构的内容的应用程序,工作方式一般基本相同。在屏幕层级的顶部,会有内容概述,然后就是多个带更多细节的屏幕。setting应用程序就是不错的示例。在顶层,一开始是setting应用的所有相关的分类,然后是能够持续向下深入,直到到达特定设置的细节。

  UINavigationController正是为了处理这种类型的导航而设。他跟踪客户,就像它位于导航中不同屏幕的层次结构,并提供默认的控件返回。该控制器通过将所有内容都嵌入它内部来实现这一点。

这里写图片描述

  上图显示了导航控制器的一部分。顶部是导航栏。导航栏通常会用在上下文中或展开的当前路径。标题通常为用户正在观看的内容。正如我们很快就会看到的一样,在导航路径中,左手边的后退按钮能够让用户返回上一节。在导航栏上,用户可以自定义按钮

  位于底部的是一个可选的工具栏,是另一处让我们设置空间的地方,上面放了一个操作按钮。我们的视图控制器位于灰色地带。而在当前场景的某个地方,需要提供一个方法来打开下一级详细页面。例如,在Add/View场景中的Edit按钮

  当使用导航控制器时,一开始可以将它连接到第一个场景或根场景(一个视图控制器)。当导航控制器打开时,他就会打开根场景。正如我们将其关联到一个新的场景(视图控制器),导航控制器会将它放在当前路径上,并显示该场景。

  在视图控制器的堆栈中,根视图位于底部,路径通常也会被记录。

介绍一下导航控制类

  所有的导航功能都通过5个主要类来提供:

  • UINavigationController为当前导航堆栈协调所有的组件。除了管理导航堆栈和所有砖厂(transition)之外,它有指向导航栏和可选工具栏的引用
  • UINavigationBar是位于屏幕顶部的导航栏视图。UINavigationController用它显示当前场景的标题和一个按钮,如果需要的话,它可以用于返回前一个界面。它可以独立地使用,但是不推荐这样做
  • UINavigationItem管理层次结构中某个特定视图控制器的UINavigationBar。它有如下各项的属性:设置标题,显示、添加和隐藏工具栏按钮,包括Back按钮
  • UIBarButtonItem提供了一个对象来管理导航和工具栏上的按钮。从系统提供按钮(如Done(完成)、Cancel(取消)和到文本按钮的操作(action)等),可以创建出任意按钮。Button Item既不是UIButton,也不是视图(View)类型。它们是管理项,可以显示用户界面中的东西。可以将UIButton放在Button Item(按钮项)里面
  • UIToolbar管理一个可选的工具栏,通常位于屏幕的底部。其拥有方法与属性来设置Button Item(按钮项)和外观,以及一种方式来指定其位置是在屏幕的顶部还是底部

      UINavigationItem使用当前视图控制器的title属性来设置文本。更改title会改变文本。之前在本地化的场景标题我们见过这个操作。

      下图显示了在CarValet应用程序的Add/View场景中与导航控制器相关的对象

这里写图片描述

  导航控制器管理Add/View场景以及其他场景。每个被管理的场景有一个UINavigationItem,用于设置导航栏的内容以及标题。Add/View场景的标题栏也有一个工具栏按钮,以显示car images场景。

  观看上图的圈圈,这是一个特殊的关联标识符(segue identifier),是为第一个控制器或根视图控制器而设。不想push segue,着开起来想一条两端都有一个圆的线。根场景是导航控制器展示的第一个场景。故事版中的另一个链接显示了场景之间的导航路径。例如在Add/View于Edit场景之间存在一个链接。因为无处可去只有返回,Edit场景就是一个叶节点,如同第一张图的叶节点。

添加工具栏

  (从书上抄了那么多字真是类,觉得还是介绍一下比较好),现在开始干正事。

  首先我们要把图标添加到项目的资产库中。我们需要图标,可以
在这里下载,但是那需要自己找;也可以在这里我的github下载。最好是从我的github上下载吧。

  好了,图标下载完了,要添加到资产库中,如下图操作方式

这里写图片描述

  选+之后,会跳出一个目录,到最下面找到Import,点完import,选中要导入的文件就行啦

这里写图片描述

这里写图片描述

  • 现在图标加进去了,我们要加底部工具栏了,打开故事面板

这里写图片描述

  • 添加完工具栏,放置按钮

这里写图片描述

这里写图片描述

  • 选择左边的按钮,Image设置为sign_out;右边那个按钮,Image设置为sign_in;中间的按钮,title改为Edit。

  • 删除原来的Previous、Next和Edit按钮,

  • 将我们之前添加的左右箭头通过下图方法设置关联,左箭头选择previousCar,右箭头选择nextCar

这里写图片描述

1

  • 当我们删除Edit按钮时,也删除了到Edit场景的关联(segue),我们要将它恢复,将它拉到Edit场景,选择push,并设置标识符为Editsegue,与之前的Edit按钮所用的关联名称一样

      然后运行程序你可能会发现下面的导航栏没有出现,那么在ViewController.m中的viewDidLoad方法中,添加self.navigationController.toolbarHidden = NO;使他正好位于[super viewDidLoad];下面,这时候就出现了,但是点开其他的例如car images,下面也出现了导航栏,这显然不是我们想要的,在Edit等场景里面也是这个情况。可以在他们各自的viewDidLoad方法中添加self.navigationController.toolbarHidden = YES;,这样就默认为隐藏了。然而还有个问题,当我们从其他场景退出返回到Add/View场景时,导航栏消失了,他也是被隐藏了,那我们就换个地方,在ViewController.m中的viewWillAppear方法中,添加self.navigationController.toolbarHidden = NO;,这样每次加载的时候,就自动设置回去了。这样就设置完成啦。

这里写图片描述

(PS,颜色是我后来弄的,到这步按钮颜色应该是蓝色的,导航栏应该是白色的,而且没有About)

基于消息的导航

到目前为止,我们已经使用segue在场景之间进行导航,包括使用特使的exit segue。我们拥有一些控制器可以传递数据并能使用prepareForSegue:方法修改行为。借助于UINavigationController的属性和消息,可以拥有完全控制权。可以实现如下类似行为:将新的视图控制器推给堆栈(push),弹出(pop)当前视图控制器,弹出根视图控制器之上的所有控制器,获取当前导航堆栈中的控制器数组,甚至重新排列视图控制器数组。

可以使用基于代码的消息,为CarValet应用程序添加一个About场景,而不是在故事面板中添加,而是可以在单独的用户界面资源文件中创建界面。在Xcode中,这些文件是XIB文件

实现步骤如下:

  • 创建一个新的Cocoa Touch Class,命名为AboutViewController,并选中“Also create XIB file”
  • 这时候多出了三个文件,将他们放到supporting files的上面
  • 打开AboutViewController.xib,这是IB文件,不支持任何脚本功能,如segue何连接。使用Attributes检查器将视图的顶部栏设置为不透明的导航栏,发现导航栏不能编辑

这里写图片描述

  • 使用Lable或其他,自行添加内容
  • 打开故事面板,添加一个About按钮。位置看上面的图。
  • 在ViewController.m中import AboutViewController.h
  • 将About拉到ViewController.h中创建action,名称为aboutCarValet
  • aboutCarValet方法代码如下:
- (IBAction)aboutCarValet:(id)sender {
    AboutViewController *nextController;

    nextController = [[AboutViewController alloc]initWithNibName:@"AboutViewController"//1
                                                          bundle:[NSBundle mainBundle]];

    nextController.title = @"About CarValet";//2
    [self.navigationController pushViewController:nextController animated:YES];
}

注释:

  1. 为AboutViewController实例初始化next Controller视图控制器。该调用用到了之前为视图控制器界面创建的XIB文件
  2. 设置About视图的标题。尅本地化该字符串
  3. 告诉导航控制器将新的视图控制器推到对战中——也就是打开并转场到该场景

运行结果:

这里写图片描述

添加颜色

  我们在IB中,有时候会看到Tint(色调)选项。使用此选项是为用户体验增加彩色主题的快速方法。需要注意的是,它与VIew区域中改变背景色是不同的。

  对UINavigationController来说,可以更改导航栏、工具栏和工具栏按钮的色调。为事物设置色调的工作由导航控制器进行管理,导航控制器会改变它管理的每个屏幕上该事物的颜色。

  打开故事面板,自行修改颜色。

这里写图片描述

  可能会遇到工具栏色调不起作用,那么我们可以用代码实现,在ViewController.m中的viewDidLoad方法下,添加

UIColor *sky = [UIColor colorWithDisplayP3Red:102.0/255.0 green:204.0/255.0 blue:255.0/255.0 alpha:1.0];
    self.navigationController.toolbar.barTintColor = sky;

  这时候颜色就添加完啦,本程序还添加了其他颜色,配色方案如下

用户界面元素苹果蜡笔颜色RGB
工具栏SKYR:102 G:204 B:255
标题snow(white)R:255 G:255 B:255
按钮MochaR:128 G:64 B:0

  但是我们上面的方法只能更改一个屏幕里面的颜色,以下代码是更改全部,在AppDelegate.m文件中

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    UIColor *Mocha = [UIColor colorWithDisplayP3Red:128.0/255 green:64.0/255.0 blue:0/255.0 alpha:1.0];

    [[UIButton appearance]setTitleColor:Mocha forState:UIControlStateNormal];
    [[UIBarButtonItem appearance] setTintColor:Mocha];
    return YES;
}

  其中,最后两行是通过appearance protocol协议修改按钮,工具栏按钮颜色。

  好了,导航控制器的使用就暂时介绍到这里咯。

1 标签栏控制器

  本想找clock程序作为用例的,模拟器上竟然没有。换成健康

这里写图片描述

  看到下面的健康数据,今天,数据来源这些选项了吧,这些是标签栏,每个栏对应不同的功能,而且有的栏里面还有多个屏幕。

工具栏的工作原理

  使用UITabBarController时,每个功能区域或标签栏都是根视图,实际上,标签栏控制器是应用程序真正的根视图,简单的画一下。

这里写图片描述

  标签栏控制器使用如下三个主要类:

  • UITabBarController管理标签栏选项卡中显示的视图控制器,并且还管理标签栏的用户交换,包括选择处理选中。如果存在5个以上选项卡,那么会展示More按钮。它也管理对额外选项卡的访问,并且管理选项卡的重新排序。
  • UITabBar是能呈现1至5个以上的选项卡的视图。每个选项卡都代表应用程序中一个不同的根视图。如果有5个以上的选项卡,那么特殊的More标签放置子在右边
  • UITabBarIter是标签栏的单个选项卡,包括两个属性分别用于标题和图像,以及一个属性用来自定义图像在被选中时的行为。
为CarValet添加标签栏

图片什么的之前已经导入了

  • 打开故事面板,选中下图

这里写图片描述

  • 选择Editor|Embed In|Tab Bar Controller

这里写图片描述

(PS,运行到这里,标签栏中应该是只有一个图标,圆形的还是方形的晚了)

  • 更换图标

这里写图片描述

  这时候是只有一个选项卡的,我就不运行了。现在我们将car image场景添加为第二个选项卡

  • 从Add/View场景中删除Car Images按钮
  • 从标签栏拉到Car Images场景,从Relationship Segue类别中选择视图控制器。这是就添加上去了。
    这里写图片描述

  • 更换图标

这里写图片描述

  • 这时候运行程序,下面有两个选项卡了(PS我这是完整版,不要在意这些细节。。。)

这里写图片描述

  然而运行的时候发现reset没用

  进行以下步骤修改:

  • 在编辑器中打开CarImageViewController.h文件,将resetZoomButton的类别改成UIButton
  • 在iPhone故事面板中,选择CarImageViewController并将一个正常的按钮拖入到顶层视图,改标题为Reset Zoom
  • 设置约束,到顶部为系统默认,到后边缘为0
  • 拖拽一个从该按钮到.h文件中的resetZoomButton实例变量的关联
  • 拖拽一个从该按钮到car image视图中发送resetZoom消息的关联
  • 在与该按钮相对应的Attributes编辑器中的Control部分,将默认值设置为不可用

ok,运行程序就行啦。

最后一点,移动的Info

  我们通过代码的形式添加about到标签栏

  • 移除Add/View中的about按钮
  • 打开ViewController.m并删除对AboutVIewController.h的引用,删除aboutCarValet:方法以及在ViewController.h中的定义
  • 打开AppDelegate.m,导入AboutVIewController.h的引用。然后修改代码如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    UIColor *Mocha = [UIColor colorWithDisplayP3Red:128.0/255 green:64.0/255.0 blue:0/255.0 alpha:1.0];

    [[UIButton appearance]setTitleColor:Mocha forState:UIControlStateNormal];
    [[UIBarButtonItem appearance] setTintColor:Mocha];

    UITabBarController *tabBarController = (UITabBarController*)self.window.rootViewController;//1
    //2
    AboutViewController *aboutViewController = [[AboutViewController alloc]initWithNibName:@"AboutViewController"
                                                                                    bundle:[NSBundle mainBundle]];
    UITabBarItem *aboutItem = [[UITabBarItem alloc]initWithTitle:@"About" //3
                                                           image:[UIImage imageNamed:@"tag"]
                                                             tag:0];
    [aboutViewController setTabBarItem:aboutItem];//4
    NSMutableArray *currentItems = [NSMutableArray arrayWithArray:tabBarController.viewControllers];//5
    [currentItems addObject:aboutViewController];//6
    [tabBarController setViewControllers:currentItems animated:NO];//7
    return YES;
}

注释:

  1. 获得对标签栏控制器的引用。
  2. 从XIB文件创建About视图控制器
  3. 为About场景创建一个标签栏选项,并设置合适的标题和图片
  4. 将About视图控制器的tabBarItem设置为新的标签栏选项。标签栏控制器会在设置标签栏选项的时候寻找该属性
  5. 基于那些由标签栏控制器进行管理的视图控制器,创建一个可变数组
  6. 将About场景添加到视图控制器数组的结尾。标签栏选项以数组中相同的顺序显示
  7. 在应用程序启动时,以不带动画效果的方式更新选项卡数组。如果该操作是在应用程序因用户行为而运行时发生,那么我们可能愿意以动画效果更新变化

      好了运行程序,再次贴图:

这里写图片描述

今天的介绍就到这里咯

我的另一个博客站点:Arnold-你们好啊

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值