UINavigationController

UINavigationController

当界面交互是:列表-->明细-->更具体的明细,这种情况就需要用UINavigationController

UINavigationController维护a stack of those screens,每一个screen都是UIViewController的view,stack是一个view controller数组。

当创建UINavigationController实例时,为其指定一个UIViewController,这个view controller就是navigation controller's root view controller,其总在stack的最下面。

和UITabBarController一样,UINavigationController也有一个viewControllers数组,root view controller是这个数组的第一个对象,当更多的view controller push到stack时,他们被添加到这个数组中,数组的最后一个对象总是在stack的顶部,UINavigationController's topViewController属性指向栈顶的view controller。

UINavigationControllerUIViewController的子类,所以他也有一个view属性,其view有两个subview:UINavigationBar和topViewController

将navigation controller设置为窗口的rootViewController

#import "BKAppDelegate.h"
#import "BKItemsViewController.h"

@implementation BKAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
   
    BKItemsViewController *itemsViewController = [[BKItemsViewController alloc] init];
    // Create an instance of UINavigationController
    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:itemsViewController];
    self.window.rootViewController = navController;
    
    
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

@end

创建BKDetailViewController

创建BKDetailViewController类,继承UIViewController类,同时创建XIB文件。


打开assistant editor

在project navigator,Option-click BKDetailViewController.m文件,打开assistant editor

simulated metrics

选择root view,然后打开attributes inspector,在Simulated Metrics section为top bar选择Translucent Navigation Bar,可以模拟navigation bar的显示


将XIB中的视图outlet到 view controller

Control-drag UITextField到view controller的class extension中。


将view controller放入navigation controller's stack

navigation controller's stack中的view controller,都可以通过navigationController方法来获得navigation controller.

root view controller创建下一个view controller,并把他放入到navigation controller stack中,然这个view controller创建下一个需要入栈的view controller,以此类推。

// 选中一行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    BKDetailViewController *detailViewController = [[BKDetailViewController alloc] init];
    [self.navigationController pushViewController:detailViewController animated:YES];
}

在view controllers之间传递数据

Having all of the data in the root view controller and passing subsets of that data to the next UIViewController is a clean and efficient way of performing this task.

为了让BKDetailViewController显示BKItem的各属性值,需要将BKItem传递给detail view controller.

在BKDetailViewController头文件中声明BKItem属性:

#import <UIKit/UIKit.h>

@class BKItem;

@interface BKDetailViewController : UIViewController

@property (nonatomic,strong) BKItem *item;

@end

当BKDetailViewController‘s view显示到屏幕上之前,将BKItem的值设置到其view上,所以在viewWillAppear:中设置

#import "BKDetailViewController.h"
#import "BKItem.h"

@interface BKDetailViewController ()
@property (weak, nonatomic) IBOutlet UITextField *nameField;
@property (weak, nonatomic) IBOutlet UITextField *serialField;
@property (weak, nonatomic) IBOutlet UITextField *valueField;
@property (weak, nonatomic) IBOutlet UILabel *dateLabel;

@end

@implementation BKDetailViewController

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    BKItem *item = self.item;
    
    self.nameField.text = item.itemName;
    self.serialField.text = item.serialNumber;
    self.valueField.text = [NSString stringWithFormat:@"%d", item.valueInDollars];
    
    static NSDateFormatter *dateFormatter = nil;
    if(!dateFormatter){
        dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.dateStyle = NSDateFormatterMediumStyle;
        dateFormatter.timeStyle = NSDateFormatterNoStyle;
    }
    self.dateLabel.text = [dateFormatter stringFromDate:item.dateCreated];
}

@end

更新BKItemsViewController.m,为BKDetailViewController传值:

// 选中一行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    BKDetailViewController *detailViewController = [[BKDetailViewController alloc] init];
    
    NSArray *items = [[BKItemStore sharedStore] allItems];
    BKItem *selectedItem = items[indexPath.row];
    
    detailViewController.item = selectedItem;
        
    [self.navigationController pushViewController:detailViewController animated:YES];
}

Appearing and disappearing views

当navigation controller切换视图时,会分别发送viewWillDisappear:viewWillAppear:到将消失和将显示的view controller

When the message endEditing: is sent to a view, if it or any of its subviews is currently the first responder, it will resign its first responder status, and the keyboard will be dismissed.

当BKDetailViewController的视图将要消失时,更新BKItem:

// 在视图要消失前,更新BKItem
- (void)viewWillDisappear:(BOOL)animated{
    
    [super viewWillDisappear:animated];
    [self.view endEditing:YES];
    
    BKItem *item = self.item;
    item.itemName = self.nameField.text;
    item.serialNumber = self.serialField.text;
    item.valueInDollars = [self.valueField.text intValue];
}

在BKItemsViewController的视图将要显示时,刷新table view:

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    [self.tableView reloadData];
}

UINavigationBar

每一个UIViewController有一个navigationItem属性,其类型是UINavigationItem,不像UINavigationBar,UINavigationItem不是UIView的子类,所以他不能出来显示在屏幕上。

当一个view controller在navigation controller的栈顶时,UINavigationBar用这个view controller的navigationItem的值来配置自己。

简单navigation item

默认,navigation item是空,最简单的navigation item,可以只配置他的title属性。

当一个view controller在navigation controller的栈顶时,并且其navigationItem有一个有效的title属性,navigation bar就会显示这个title。

修改BKItemsViewController.m,在初始化时设置navigationItem's title:

- (instancetype)init{
    self = [super initWithStyle:UITableViewStylePlain];
    
    if(self){
        // 设置其本身的navigationItem
        UINavigationItem *navItem = self.navigationItem;
        navItem.title = @"Homepwner";
    }
       
    return self;
}

当为BKDetailViewController设置BKItem时(set方法),设置其navigationItem title为BKItem's name。

- (void)setItem:(BKItem *)item{
    _item = item;
    self.navigationItem.title = _item.itemName;
}

复杂navigation item

navigation item不光可以只定义title属性,还可以很复杂。如下图所示,每个UINavigationItem有三个可自定义区:leftBarButtonItem,rightBarButtonItem,titleView。
前两个是UIBarButtonItem实例,这个类型的实例只能用来配置UINavigationBar或UIToolbar中的button的显示内容。

和UINavigationItem一样,UIBarButtonItem也不是UIView的子类,所以不能显示在屏幕上。

第三个titleView,可以是一个基本的title字符串,也可以是任意的UIView子类,只能任选一种。

下面将BKItemsViewController的headerView(自定义的view)替换成UINavigationBar。

navigation bar 的button,和UIControl 的target-action机制一样,当被点击,发送action消息到target。
在XIB中设置target-action pair,Control-drag button组件到target,并选择IBAction list中的一个。
也可以通过代码的方式,创建target-action pair,传递target和action到button.

在BKItemsViewController.m文件,创建UIBarButtonItem实例,并为其传递target和action。

- (instancetype)init{
    self = [super initWithStyle:UITableViewStylePlain];
    
    if(self){
        // 设置其本身的navigationItem
        UINavigationItem *navItem = self.navigationItem;
        navItem.title = @"Homepwner";
        
        // 创建一个bar button item,并设置target action
        UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addNewItem:)];
        // 将bar button item设置给navigation item
        navItem.rightBarButtonItem = bbi;
        
        navItem.leftBarButtonItem = self.editButtonItem;
    }
       
    return self;
}

action传递的是一个SEL类型,这个类型指定一个方法(就是selector),@selector()不关心返回类型,参数类型或参数名称。

UIViewController有一个editButtonItem属性,当调用这个属性,view controller创建一个title为Edit的UIBarButtonItem,并且已经设置好了target-action,当被点击时,发送setEditing:animated:消息到UIViewController。

现在可以把自定义的headerView删除了。


本文是对《iOS Programming The Big Nerd Ranch Guide 4th Edition》第十章的总结。

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

推荐阅读更多精彩内容