你的位置:首页 > 操作系统

[操作系统]iOS Programming UINavigationController


iOS Programming UINavigationController

the Settings application has multiple related screens of information: a list of settings (like Sounds), a detailed page for each setting, and a selection page for each detail. This type of interface is called a drill-down interface.

setting application 有许多屏幕相关的信息:一系列的settings,每个setting的一个detail page和为每个detail page 的一个selection page。

这种类型的interface成为drill-down interface.

1 UINavigationController

When your application presents multiple screens of information, a UINavigationController maintains a stack of those screens.

当你的应用要展现多个屏幕信息的时候,UINavigationController保持了一个栈的这个样的屏幕。

Each screen is the view of a UIViewController,

每个屏幕就是一个UIViewController的view。

and the stack is an array of view controllers.

这个stack 就是一列view controller。

When a UIViewController is on top of the stack, its view is visible.

当一个UIViewController 在stack 的顶部,那么它的view 是可见的。

When you initialize an instance of UINavigationController, you give it one UIViewController. This UIViewController is the navigation controller's root view controller.

当你初始化UINavigationController,你就给它了一个UIViewController。这个UIViewController是navigationcontroller 的root view controller .

The root view controller is always on the bottom of the stack. More view controllers can be pushed on top of the UINavigationController's stack while the application is running.

The root view controller 总是在stack 的底部。当application运行的时候,更多地更控制被放在了UINavigationController's stack 的顶部。

When a UIViewController is pushed onto the stack, its view slides onto the screen from the right. When the stack is popped, the top view controller is removed from the stack and its view slides off to the right, exposing the view of next view controller on the stack.

当UIViewController被放进stack,它的view 将从屏幕的右边滑进来。当stack  is popped,the top view controller  将被移除,并且它的view 也将从右边滑出,展现出在stack 上的下一个view controller 

 

 

The root view controller is the first object in the array. As more view controllers are pushed onto the stack, they are added to the end of this array.

The root view controller 是列的第一个对象。当更多地 view controllers被推送到stack 上,他们被添加到数组的最后。

Thus, the last view controller in the array is the top of the stack. UINavigationController's topViewController property keeps a pointer to the top of the stack.

因此数组的the last view controller  是stack 的顶部。UINavigationController's的topViewController property 有一个指针指向stack 的顶部。

 

UINavigationController is a subclass of UIViewController, so it has a view of its own. Its view always has two subviews: a UINavigationBar and the view of topViewController

UINavigationController是UIViewController的一个子类,因此它有一个他自己的view。它的view总是有两个subviews:一个是UINavigationBar,另一个是topViewController的view。

You can set a navigation controller as the rootViewController of the window to make its view a subview of the window.

你可以设置navigation controller为window的rootViewController,从而使它的view 成为window的subview。

1.1

The only requirements for using a UINavigationController are that you give it a root view controller and add its view to the window.

你想用UINavigationController,你就把它给rootviewcontroller ,并把它的view 添加到window。

UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:itemViewController];

    self.window.rootViewController=navigationController;

2 An Additional UIViewController

Create a new Objective-C class (File → New → File...). Name this class BNRDetailViewController and choose UIViewController as the superclass. Check the With XIB for user interface box

3 Navigating with UINavigationController

          3.1 Pushing view controllers

The viewControllers array of a navigation controller is dynamic – you start with a root view controller and push view controllers depending on user input.

The viewControllers array of a navigation controller是动态的 -你开始一个root view controller 并且根据你的输入,推送view Controller 。

Therefore, some object other than the navigation controller needs to create the instance of BNRDetailViewController and be responsible for adding it to the stack.

因此,除了navigation controller 之外还有其他的对象需要创建BNRDetailViewController的实例,并负责把它添加到stack 中。

 

This object must meet two requirements: it needs to know when to push a BNRDetailViewController onto the stack, and it needs a pointer to the navigation controller to send the navigation controller messages, namely, pushViewController:animated:.

这个对象需要满足两个要求(1) 它需要知道什么时候把BNRDetailViewController放入到stack 上。(2) 它需要指针指向 navigation controller 发送navigation controller信息,名字为pushViewController:animated。 

 

BNRItemsViewController fills both requirements. First, it knows when a row is tapped in a table view because, as the table view's delegate, it receives the message tableView:didSelectRowAtIndexPath: when this event occurs.

BNRItemsViewController满足以上两条(1) 它知道什么时候在table view中的一行被选中,作为table view的委托,当这个时间发生时,它接受tableView:didSelectRowAtIndexPath的消息。

Second, any view controller in a navigation controller's stack can get a pointer to that navigation controller by sending itself the message navigationController.As the root view controller, BNRItemsViewController is always in the navigation controller's stack and thus can always access it.

(2)任何 在navigation controller's stack中view controller 都有一个指向navigation controller的指针,通过向自己发送navigationController消息。

 

Therefore, BNRItemsViewController will be responsible for creating the instance of BNRDetailViewController and adding it to the stack.

#import "BNRDetailViewController.h"

- (void)tableView:(UITableView *)tableView

didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

BNRDetailViewController *detailViewController =[[BNRDetailViewController alloc] init];

// Push it onto the top of the navigation controller's stack

[self.navigationController pushViewController:detailViewController]

}

Since the UINavigationController's stack is an array, it will take ownership of any view controller added to it.

因为UINavigationController's stack 是一个数组,它可以拥有任意类型的view Controller。

Thus, the BNRDetailViewController is owned only by the UINavigationController after tableView:didSelectRowAtIndexPath: finishes. When the stack is popped, the BNRDetailViewController is destroyed. The next time a row is tapped, a new instance of BNRDetailViewController is created.

因此BNRDetailViewController仅仅当tableView:didSelectRowAtIndexPath完成后才被UINavigationController拥有。当这个stack 被poped ,BNRDetailViewController将被销毁。

          3.2 Passing data between view controllers

To fill these fields, you need a way to pass the selected BNRItem from the BNRItemsViewController to the BNRDetailViewController.

为了填充空白,你需要用一种方式把选中的从BNRItemsViewController 得到的BNRItem 传递给BNRDetailViewController。

To pull this off, you will give BNRDetailViewController a property to hold a BNRItem.

为了胜利完成这个,你需要给BNRDetailViewController一个属性来拥有BNRItem。

When a row is tapped, BNRItemsViewController will give the corresponding BNRItem to the instance of BNRDetailViewController that is being pushed onto the stack.

当一行被选中后,BNRItemsViewController将给对应的BNRItem传递给将要进入stack的BNRDetailViewController。

The BNRDetailViewController will populate its text fields with the properties of that BNRItem.

BNRDetailViewController将会显示拥有那个BNRItem属性的text field .

Editing the text in the text fields on BNRDetailViewController's view will change the properties of that BNRItem.

编辑在BNRDetailViewController's view中 text field 中得text将会改变那个BNRItem的属性。

#import <UIKit/UIKit.h>
@class BNRItem;

@interface BNRDetailViewController : UIViewController

@property (nonatomic, strong) BNRItem *item;

@end

 

When the BNRDetailViewController's view appears on the screen, it needs to set up its subviews to show the properties of the item.

当BNRDetailViewController's的view 显示在屏幕上时,它需要设置它的subview 来显示item的属性

- (void)viewWillAppear:(BOOL)animated

{
[super viewWillAppear:animated];

BNRItem *item = self.item;

self.nameField.text = item.itemName; self.serialNumberField.text = item.serialNumber; self.valueField.text = [NSString stringWithFormat:@"%d",

item.valueInDollars];

// You need an NSDateFormatter that will turn a date into a simple date string

static NSDateFormatter *dateFormatter = nil; if (!dateFormatter) {

dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateStyle = NSDateFormatterMediumStyle; dateFormatter.timeStyle = NSDateFormatterNoStyle;

}

// Use filtered NSDate object to set dateLabel contents

self.dateLabel.text = [dateFormatter stringFromDate:item.dateCreated]; }

 

In BNRItemsViewController.m, add the following code to tableView:didSelectRowAtIndexPath: so that BNRDetailViewController has its item before viewWillAppear: gets called.

 

NSArray *items = [[BNRItemStore sharedStore] allItems]; BNRItem *selectedItem = items[indexPath.row];

// Give detail view controller a pointer to the item object in row detailViewController.item = selectedItem;

 

          3.3how data is passed between view controllers?

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

让root view controller 拥有所有数据,然后传递给下一个UIViewController是一个有效和干净的方式传递这些数据。

 

          3.4 Appearing and disappearing views

Whenever a UINavigationController is about to swap views, it sends out two messages: viewWillDisappear: and viewWillAppear:.

当UINavigationController将要切换view时,它会发送两个消息viewWillDisappear和viewWillAppear。

The UIViewController that is about to be popped off the stack is sent the message viewWillDisappear:. The UIViewController that will then be on top of the stack is sent viewWillAppear:.

那个将要从stack 中popped 的UIViewController被发送为viewWillDisappear。那个将要添加到stack 顶部的UIViewController将会被发送viewWillAppear。

When a BNRDetailViewController is popped off the stack, you will set the properties of its item to the contents of the text fields.

当一个BNRDetailViewController从stack删除的时候,它就会设置它的item属性为text field 的内容。

When implementing these methods for views appearing and disappearing, it is important to call the superclass's implementation – it might have some work to do and needs to be given the chance to do it.

当实现这些方法的时候,调用superclass 的实现很重要。它可能有一些工作要做,你应该给它这个机会。

- (void)viewWillDisappear:(BOOL)animated

{
[super viewWillDisappear:animated];

// Clear first responder [self.view endEditing:YES];

// "Save" changes to item

BNRItem *item = self.item;

item.itemName = self.nameField.text; item.serialNumber = self.serialNumberField.text; item.valueInDollars = [self.valueField.text intValue];

     3.4.1

Notice the use of endEditing:. 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. (The argument passed determines whether the first responder should be forced into retirement. Some first responders might refuse to resign, and passing YES ignores that refusal.)

主要到endEditing得使用。

当endEditing 被发给一个view ,那么这个view 以及它的任意subviews 如果是 currently first  responder,它将resign  first responder 的状态,并且keyboard将会消失。

 

Now the values of the BNRItem will be updated when the user taps the Back button on the UINavigationBar.
当用户tap  back button ,那么BNRItem将会更新。
When BNRItemsViewController appears back on the screen, it is sent the message viewWillAppear:. Take this opportunity to reload the UITableView so the user can immediately see the changes.
当BNRItemsViewController显示到屏幕上时,它会被发送一个viewWillAppear的消息。这是一个重新加载UITableView数据的机会。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData]; }

很困惑如何保存到[BNRItemStore sharedStore]的。 
4 . UINavigationBar
Every UIViewController has a navigationItem property of type UINavigationItem. However, unlike UINavigationBar, UINavigationItem is not a subclass of UIView, so it cannot appear on the screen.
每一个UIViewController都有一个UINavigationItem类型的navigationItem 属性。与UINavigationBar不同的是UINavigationItem并不是UIView 的子类,所以它不能显示在屏幕上。
Instead, the navigation item supplies the navigation bar with the content it needs to draw.
取而代之的是navigation item提供了navigation bar 需要绘制 的内容。
When a UIViewController comes to the top of a UINavigationController's stack, the UINavigationBar uses the UIViewController's navigationItem to configure itself
当一个UIViewController在UINavigationController'的顶部时,这个UINavigationBar用UIViewController的navigationItem来配置自己。

By default, a UINavigationItem is empty.
默认情况下,一个UINavigationItem是空的。
At the most basic level, a UINavigationItem has a simple title string.
UINavigationItem有一个简单地标题字符串。
When a UIViewController is moved to the top of the navigation stack and its navigationItem has a valid string for its title property, the navigation bar will display that string
当UIViewController被移动到navigation stack 顶部时,它的navigationItem有一个有效的string,那么navigation bar将会显示这个 string。
In BNRItemsViewController.m, modify init to set the navigationItem's title to read Homepwner.
- (instancetype)init
{
self = [super initWithStyle:UITableViewStylePlain]; if (self) {
UINavigationItem *navItem = self.navigationItem; navItem.title = @"Homepwner";
}
return self; }

It would be nice to have the BNRDetailViewController's navigation item title be the name of the BNRItem it is displaying. Obviously, you cannot do this in init because you do not yet know what its item will be.
明显的,你不能在init 方法中赋值,因为这时,你还不知道它的item是什么。
, the BNRDetailViewController will set its title when it sets its item property. In BNRDetailViewController.m, implement setItem:, replacing the synthesized setter method for item.
你可以重写setItem,在setItem中重写该方法。
- (void)setItem:(BNRItem *)item
{
_item = item;
self.navigationItem.title = _item.itemName; }

4.1 There are three customizable areas for each UINavigationItem: a leftBarButtonItem, a rightBarButtonItem, and a titleView.
每个UINavigationItem有三个通用的区域:leftBarButtonItem,rightBarButtonItem,titleView。
The left and right bar button items are pointers to instances of UIBarButtonItem, which contains the information for a button that can only be displayed on a UINavigationBar or a UIToolbar.
左边和右边的bar button items 有指针指向UIBarButtonItem的实例。该实例包含了只能在UINavigationBar或者是UIToolbar上显示的button 信息。

Like UINavigationItem, UIBarButtonItem is not a subclass of UIView.
UIBarButtonItem像UINavigationItem也不是UIView 的子类。
Instead, UINavigationItem encapsulates information that UINavigationBar uses to configure itself.
UINavigationItem概况了UINavigationBar配置自己需要的信息。
Similarly, UIBarButtonItem is not a view, but holds the information about how a single button on the UINavigationBar should be displayed.
相似的,UIBarButtonItem也不是个view,但是拥有怎样在UINavigationBar显示的一个button的信息。
(A UIToolbar also uses instances of UIBarButtonItem to configure itself.)
一个UIToolBar 也是用UIBarButtonItem的实例来配置自己。
The third customizable area of a UINavigationItem is its titleView.
第三个适应区域是它的titleView。 
You can either use a basic string as the title or have a subclass of UIView sit in the center of the navigation item. You cannot have both.
你可以用一个基本的string作为titile或者有一个UIView 的子类在navigation item 的中心。你不能同时有这两个。

A bar button item has a target-action pair that works like UIControl's target-action mechanism: when tapped, it sends the action message to the target.
一个bar button item  有一个target-action pair就像UIcontrol 的target-action 机制:当点击时,它发送一个action 消息给target.

let's add another UIBarButtonItem to replace the Edit button in the table view header. In BNRItemsViewController.m, edit the init method.
navItem.leftBarButtonItem = self.editButtonItem;
Where does editButtonItem come from?
这个editButtonItem从哪来的?
UIViewController has an editButtonItem property, and when sent editButtonItem, the view controller creates a UIBarButtonItem with the title Edit.
Even better, this button comes with a target- action pair: it sends the message setEditing:animated: to its UIViewController when tapped.
这个button有一个target-action pair:当点击的时候它发送setEditing:animated给UIViewController。 

5 bug

bug:Cannot find executable for CFBundle 0x8f92720 </Applications/xcode5/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk/System/Library/AccessibilityBundles/CertUIFramework.axbundle> (not loaded)

 

解决办法:Temporary workaround: click iOS Simulator > Reset Content and Settings... and run again.
这个错误会随机出现。这应该是Xcode 的一个错误吧。