我們知道 UITabBarController 對象,可以通過使用該對象,用戶可以切換不同的屏幕。當要切換的各個屏幕之間沒有相互依存關系的時候,該對象可以很好的完成任務。但是當多個屏幕互有關系的時候,就要使用另一種控制器 UINavigationController 。 事實上,基本上在所有的 APP 中,必不可少的兩種控制器。
我們以 iOS 自帶的 設置 應用為例,設置應用擁有多個互有關聯的窗口,我們稱之為這種界面為 垂直界面 。
下面我們將使用 UINavigationController 對象將 JXHomepwner 對象加入到 垂直界面 。項目地址
- UINavigationController 對象
當某個應用通過 UINavigationController 對象顯示多個屏幕的信息時,相應的 UINavigationController 對象會以棧的形式保存所有屏幕的信息。這里的棧是一個數組對象,保存的都是 UIViewController 對象。一個 UIViewController 對象的視圖對應一個屏幕。只用位於棧頂的 UIViewController 對象,其視圖才是可見的。
初始化 UINavigationController 對象時,需要傳入一個 UIViewController 對象。這個 UIViewController 對象將成為 UINavigationController 對象的 根視圖控制器(root view controller),且根視圖控制器將永遠位於棧底。應用可以在運行時向 UINavigationController 的棧底壓入更多的視圖控制器。
將某個視圖控制器壓入 UINavigationController 對象的棧時,新加入的視圖控制器的視圖會從窗口右側推入。出棧時, UINavigationController 對象會移除位於棧頂的視圖控制器,其視圖會向窗口右側推出,然后用戶會看見僅次於棧頂位置的視圖控制器的視圖。
類似於 UITabBarController 對象, UINavigationController 對象有一個名為 viewControllers 的屬性,指向一個負責保存視圖控制器的數組對象。在這個數組對象中,根視圖控制器是第一個對象。當應用將某個視圖控制器壓入棧后,UINavigationController 對象會將新加入的對象加在 viewControllers 數組的末尾。因此,該數組中的最后一個視圖控制器會位於棧的頂部。UINavigationController 對象的 topViewController 屬性是一個指針,指向當前位於棧頂的視圖控制器。
UINavigationController 是 UIViewController 的子類,所以 UINavigationController 對象也有自己的視圖。該對象的視圖有兩個子視圖:一個是 UINavigationBar 對象,另一個是 topViewController 的視圖。和其他視圖控制器一樣,可以將 UINavigationController 對象設置為 UIWindow 對象的 rootViewController ,從而將該對象的視圖作為子視圖加入窗口。
首先為項目添加一個 UINavigationController 對象。
#import "AppDelegate.h" #import "JXItemsViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // 添加初始化代碼 // 創建 JXItemsViewController 對象 JXItemsViewController * itemsViewController = [[JXItemsViewController alloc] init]; // 將 JXItemsViewController 的標示圖加入窗口 self.window.rootViewController = itemsViewController; // 將 UINavigationController 對象設置為 UIWindow 對象的根視圖控制器。 // 這樣就可以將 UINavigationController 對象的視圖添加到屏幕中 UINavigationController * navController = [[UINavigationController alloc] initWithRootViewController:itemsViewController]; self.window.rootViewController = navController; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
構建並運行,除了屏幕頂部新出現的 UINavigationController 對象,真個應用看上去跟之前沒有任何差別。JXItemsViewController 對象的視圖大小會發生變化以適應帶 UINavigationBar 對象的屏幕。這項工作是由 UINavigationController 完成的。
- 額外的視圖控制器
要讓 JXHomepwner 的 UINavigationController 對象真正的發揮作用,還要將另一個視圖控制器壓入 UINavigationController 對象的棧中。創建新的控制器,同時勾選 XIB。
下面我們需要為應用添加功能:當用戶點擊 UITableView 對象中的某個表格行時,應用需要顯示一個新的屏幕。針對選中的 JXItem 對象的每一個屬性,這個心得屏幕都要顯示一個可以編輯的文本框。負責顯示 JXItem 對象信息的視圖應該由 JXDetailViewController 控制。
為了顯示 JXItem 對象的四個屬性,需要在 JXDetialViewController 中為每一個屬性創建一個視圖並聲明相應的插座變量。
創建關聯時,需要執行獨立三步:1.在頭文件中聲明插座變量。2.在 XIB 文件中設置界面。3.在 XIB 文件中創建關聯。
設置視圖的時候請注意不要將這些子視圖放置在 view 最頂端。在視圖控制器中,view 會襯於 UINavigationBar 的下方,導致 UINavigationBar 會遮擋 view 最頂端的內容(對於 UITabBar 也是同樣的情況,因此也不要將子視圖放置在 view 的最低端)。關聯后的代碼。
#import "JXDetailViewController.h" @interface JXDetailViewController () @property (weak, nonatomic) IBOutlet UITextField *nameField; @property (weak, nonatomic) IBOutlet UITextField *seriaNumberField; @property (weak, nonatomic) IBOutlet UITextField *valueField; @property (weak, nonatomic) IBOutlet UILabel *dateLabel; @end @implementation JXDetailViewController - (void)viewDidLoad { [super viewDidLoad]; } @end
設置 XIB 文件時,要確保其中的關聯都是正確的,這點非常重要。產生錯誤關聯常見的原因為:我們修改了某個插座變量的便令名,但是沒有更新 XIB 文件中的相應關聯;或者我們徹底刪除了某個插座變量,但是沒有刪除 XIB 文件中的相應關聯。
下面要在 xib 中創建針對每一個 UITextField 對象,將其 delegate 屬性關聯至 File's Owner (按住 Control , 從 UITextField 對象拖拽置 File's Owner ,然后選擇彈出菜單中的 delegate)。
- UINavigationController 的導航功能
前面我們已經加入了一個 UINavigationController 對象。下面我們就需要將我們所需的對象組合在一起。
將視圖控制器壓入棧
如果想要完成目標,就需要創建 JXDetailViewController 對象。但是我們需要知道如何,何時,在哪里創建這個控制器。所以這個 UINavigationController 對象的 viewControllers 數組是動態的:一開始只有一個根視圖,應用需要根據情況來推出新的視圖控制器。因此,應用需要某個對象來負責創建 JXDetailViewController 對象,並將新的創建的對象壓入 UINavigationController 對象的棧。
這個負責創建 JXDetailViewController 對象的對象需要滿足兩個條件:首先,因為該對象是 UITableView 對象的委托,所以當用戶點擊 UITableView 對象的某個表格行時,JXItemsViewController 對象就會收到
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
其次,凡是加入了某個 UINavigationController 對象的棧的視圖控制器,都可以向自己發送 navigationController 消息,以得到指向該對象的指針。因為應用會將 JXItemsViewController 對象設置為 UINavigationController 對象的根視圖控制器,所以 JXItemsViewController 對象會一直停留在 UINavigationController 對象的棧中,從而使JXItemsViewController 對象總能得到指向響應 UINavigationController 的指針。
因此,應該由 JXItemsViewController 對象負責創建 JXDetailViewController 對象並將其加入到 UINavigationController 對象的棧中。
#import "JXItemsViewController.h" #import "JXItem.h" #import "JXItemStore.h" #import "JXDetailViewController.h" @interface JXItemsViewController () /** 頭部視圖 */ @property (nonatomic,weak) UIView * headerView; /** 編輯按鈕 */ @property (nonatomic,strong) UIButton * editButton; /** 增加按鈕 */ @property (nonatomic,strong) UIButton * addButton; @end @implementation JXItemsViewController - (instancetype)init { // 調用父類的指定初始化方法 self = [super initWithStyle:UITableViewStylePlain]; if (self) { for (NSInteger i=0; i<5; i++) { [[JXItemStore sharedStore] createItem]; } } return self; } - (instancetype)initWithStyle:(UITableViewStyle)style { return [self init]; } - (void)viewDidLoad { [super viewDidLoad]; // 向控制器注冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; // 加載頭視圖 [self headerView]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[JXItemStore sharedStore] allItem] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 創建 UITableViewCell 對象,風格使用默認風格 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath]; // 獲取 allItem 的第 n 個 JXItem 對象 // 然后將該 JXItem 對象的描述信息賦值給 UITableViewCell 對象的 textLabel // 這里的 n 是該 UITableViewCell 對象所對應的表格索引 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; cell.textLabel.text = [item description]; return cell; } /** * 刪除行 * * @param tableView 對象 * @param editingStyle 操作 * @param indexPath 操作的行數 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // 如果tableView請求的是刪除對象 if (editingStyle == UITableViewCellEditingStyleDelete) { // 取出需要刪除的對象 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; // 刪除對象 [[JXItemStore sharedStore] removeItem:item]; // 刷新表格 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } /** * 移動行 * * @param tableView 對象 * @param sourceIndexPath 需要移動的行 * @param destinationIndexPath 目標行 */ - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { [[JXItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row]; } #pragma mark - UITalbeViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { JXDetailViewController * detailController = [[JXDetailViewController alloc] init]; // 將新創建的控制器壓入到導航控制器對象棧中 [self.navigationController pushViewController:detailController animated:YES]; } #pragma mark - 懶加載 - (UIView *)headerView{ if (_headerView == nil) { UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; // 設置頭部視圖 self.tableView.tableHeaderView = headerView; headerView.backgroundColor = [UIColor cyanColor]; [headerView addSubview:self.editButton]; [headerView addSubview:self.addButton]; _headerView = headerView; } return _headerView; } - (UIButton *)editButton{ if (_editButton == nil) { _editButton = [UIButton buttonWithType:UIButtonTypeCustom]; _editButton.frame = CGRectMake(0, 0, self.view.bounds.size.width / 2, 50); [_editButton setTitle:@"Edit" forState:UIControlStateNormal]; _editButton.backgroundColor = [UIColor greenColor]; [_editButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [_editButton addTarget:self action:@selector(editClick:) forControlEvents:UIControlEventTouchDown]; } return _editButton; } - (UIButton *)addButton{ if (_addButton == nil) { UIButton * addButton = [UIButton buttonWithType:UIButtonTypeCustom]; addButton.frame = CGRectMake(self.view.bounds.size.width / 2, 0, self.view.bounds.size.width / 2, 50); [addButton setTitle:@"Add" forState:UIControlStateNormal]; addButton.backgroundColor = [UIColor blueColor]; [addButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [addButton addTarget:self action:@selector(addClick:) forControlEvents:UIControlEventTouchDown]; _addButton = addButton; } return _addButton; } #pragma mark - 點擊事件 - (void)editClick:(UIButton *)sender { if (self.isEditing) { // 如果是編輯狀態,取消編輯 // 更改文字 [sender setTitle:@"Edit" forState:UIControlStateNormal]; // 取消編輯 [self setEditing:NO animated:YES]; } else { // 更改文字 [sender setTitle:@"Done" forState:UIControlStateNormal]; // 開始編輯 [self setEditing:YES animated:YES]; } } /** * 添加表格時,必須保證 UITableView 對象當前顯示的行數與數據源的提供的行數相同。 * 所以,在添加之前,必須先創建一個新的 JXItem 對象並加入到 JXItemStore 中 * * @param sender 按鈕 */ - (void)addClick:(UIButton *)sender { // 創建新的 JXItem 對象,並加入到 JXItemStore 中 JXItem * newItem = [[JXItemStore sharedStore] createItem]; // 獲取新的對象在 allItem 數組中的索引 NSInteger lastRow = [[[JXItemStore sharedStore] allItem] indexOfObject:newItem]; NSIndexPath * indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0]; // 將新航插入 UITableView 對象 [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; } @end
視圖控制器之間的數據傳遞
下面為push進來的控制器設置顯示內容。
首先為 JXDetailViewController 添加一個屬性,用來保存指定的 JXItem 對象。當用戶點擊 UITableView 對象中的某個行時,JXItemsViewController 對象應該將選中的 JXItem 對象傳給即將壓入棧的 JXDetailViewController 對象。得到 JXItem 對象后,JXDetailViewController 對象就可以針對相應的 JXItem 屬性設置所有的 UITextField 對象。
#import <UIKit/UIKit.h> @class JXItem; @interface JXDetailViewController : UIViewController /** 接收參數 */ @property (nonatomic,strong) JXItem * item; @end
#import "JXDetailViewController.h" #import "JXItem.h" @interface JXDetailViewController () @property (weak, nonatomic) IBOutlet UITextField *nameField; @property (weak, nonatomic) IBOutlet UITextField *seriaNumberField; @property (weak, nonatomic) IBOutlet UITextField *valueField; @property (weak, nonatomic) IBOutlet UILabel *dateLabel; @end @implementation JXDetailViewController - (void)viewDidLoad { [super viewDidLoad]; JXItem * item = self.item; self.nameField.text = item.itemName; self.seriaNumberField.text = item.itemName; self.valueField.text = [NSString stringWithFormat:@"%ld",item.valueInDollars]; // 創建 NSDdateFoemateter 對象,用於將 NSDate 對象轉換成簡單的日期字符串 static NSDateFormatter * dateFormatter = nil; if (!dateFormatter) { dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateStyle = NSDateFormatterMediumStyle; dateFormatter.timeStyle = NSDateFormatterNoStyle; } // 將轉換后得到的日期字符串設置為 dateLabel 的標題 self.dateLabel.text = [dateFormatter stringFromDate:item.createDate]; } @end
#import "JXItemsViewController.h" #import "JXItem.h" #import "JXItemStore.h" #import "JXDetailViewController.h" @interface JXItemsViewController () /** 頭部視圖 */ @property (nonatomic,weak) UIView * headerView; /** 編輯按鈕 */ @property (nonatomic,strong) UIButton * editButton; /** 增加按鈕 */ @property (nonatomic,strong) UIButton * addButton; @end @implementation JXItemsViewController - (instancetype)init { // 調用父類的指定初始化方法 self = [super initWithStyle:UITableViewStylePlain]; if (self) { for (NSInteger i=0; i<5; i++) { [[JXItemStore sharedStore] createItem]; } } return self; } - (instancetype)initWithStyle:(UITableViewStyle)style { return [self init]; } - (void)viewDidLoad { [super viewDidLoad]; // 向控制器注冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; // 加載頭視圖 [self headerView]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[JXItemStore sharedStore] allItem] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 創建 UITableViewCell 對象,風格使用默認風格 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath]; // 獲取 allItem 的第 n 個 JXItem 對象 // 然后將該 JXItem 對象的描述信息賦值給 UITableViewCell 對象的 textLabel // 這里的 n 是該 UITableViewCell 對象所對應的表格索引 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; cell.textLabel.text = [item description]; return cell; } /** * 刪除行 * * @param tableView 對象 * @param editingStyle 操作 * @param indexPath 操作的行數 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // 如果tableView請求的是刪除對象 if (editingStyle == UITableViewCellEditingStyleDelete) { // 取出需要刪除的對象 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; // 刪除對象 [[JXItemStore sharedStore] removeItem:item]; // 刷新表格 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } /** * 移動行 * * @param tableView 對象 * @param sourceIndexPath 需要移動的行 * @param destinationIndexPath 目標行 */ - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { [[JXItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row]; } #pragma mark - UITalbeViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { JXDetailViewController * detailController = [[JXDetailViewController alloc] init]; NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * selectedItem = items[indexPath.row]; // 將選中的JXItem 對象賦給 DetailViewController 對象 detailController.item = selectedItem; // 將新創建的控制器壓入到導航控制器對象棧中 [self.navigationController pushViewController:detailController animated:YES]; } #pragma mark - 懶加載 - (UIView *)headerView{ if (_headerView == nil) { UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; // 設置頭部視圖 self.tableView.tableHeaderView = headerView; headerView.backgroundColor = [UIColor cyanColor]; [headerView addSubview:self.editButton]; [headerView addSubview:self.addButton]; _headerView = headerView; } return _headerView; } - (UIButton *)editButton{ if (_editButton == nil) { _editButton = [UIButton buttonWithType:UIButtonTypeCustom]; _editButton.frame = CGRectMake(0, 0, self.view.bounds.size.width / 2, 50); [_editButton setTitle:@"Edit" forState:UIControlStateNormal]; _editButton.backgroundColor = [UIColor greenColor]; [_editButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [_editButton addTarget:self action:@selector(editClick:) forControlEvents:UIControlEventTouchDown]; } return _editButton; } - (UIButton *)addButton{ if (_addButton == nil) { UIButton * addButton = [UIButton buttonWithType:UIButtonTypeCustom]; addButton.frame = CGRectMake(self.view.bounds.size.width / 2, 0, self.view.bounds.size.width / 2, 50); [addButton setTitle:@"Add" forState:UIControlStateNormal]; addButton.backgroundColor = [UIColor blueColor]; [addButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [addButton addTarget:self action:@selector(addClick:) forControlEvents:UIControlEventTouchDown]; _addButton = addButton; } return _addButton; } #pragma mark - 點擊事件 - (void)editClick:(UIButton *)sender { if (self.isEditing) { // 如果是編輯狀態,取消編輯 // 更改文字 [sender setTitle:@"Edit" forState:UIControlStateNormal]; // 取消編輯 [self setEditing:NO animated:YES]; } else { // 更改文字 [sender setTitle:@"Done" forState:UIControlStateNormal]; // 開始編輯 [self setEditing:YES animated:YES]; } } /** * 添加表格時,必須保證 UITableView 對象當前顯示的行數與數據源的提供的行數相同。 * 所以,在添加之前,必須先創建一個新的 JXItem 對象並加入到 JXItemStore 中 * * @param sender 按鈕 */ - (void)addClick:(UIButton *)sender { // 創建新的 JXItem 對象,並加入到 JXItemStore 中 JXItem * newItem = [[JXItemStore sharedStore] createItem]; // 獲取新的對象在 allItem 數組中的索引 NSInteger lastRow = [[[JXItemStore sharedStore] allItem] indexOfObject:newItem]; NSIndexPath * indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0]; // 將新航插入 UITableView 對象 [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; } @end
雖然我們已經成功的將數據傳入到下一個控制器中,但是當屏幕返回 JXItemsViewController 對象后,UITableView 對象不會根據用戶修改來顯示更新內容。
視圖的顯示和消失
當 UINavigationController 對象切換視圖時,其包含的兩個 UIViewController 對象會分別收到 viewWillDisappear: 消息和 viewWillAppear: 消息。即將出棧的 UIViewController 對象會收到 viewWillDisappear: 消息,即將入棧的 UIViewController 對象會收到 viewWillAppear: 消息。
當某個 JXDetailViewController 對象退出棧時,應該將各個 UITextField 對象的值賦給 JXItem 對象的相應屬性。覆蓋 viewWillDisappear: 和 viewWillAppear: 時,必須先調用其父類實現。
#import "JXDetailViewController.h" #import "JXItem.h" @interface JXDetailViewController () @property (weak, nonatomic) IBOutlet UITextField *nameField; @property (weak, nonatomic) IBOutlet UITextField *seriaNumberField; @property (weak, nonatomic) IBOutlet UITextField *valueField; @property (weak, nonatomic) IBOutlet UILabel *dateLabel; @end @implementation JXDetailViewController - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 取消當前的第一響應對象 [self.view endEditing:YES]; // 將修改保存到 JXItem JXItem * item = self.item; item.itemName = self.nameField.text; item.serialnumber = self.seriaNumberField.text; item.valueInDollars = [self.valueField.text integerValue]; } - (void)viewDidLoad { [super viewDidLoad]; JXItem * item = self.item; self.nameField.text = item.itemName; self.seriaNumberField.text = item.itemName; self.valueField.text = [NSString stringWithFormat:@"%ld",item.valueInDollars]; // 創建 NSDdateFoemateter 對象,用於將 NSDate 對象轉換成簡單的日期字符串 static NSDateFormatter * dateFormatter = nil; if (!dateFormatter) { dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateStyle = NSDateFormatterMediumStyle; dateFormatter.timeStyle = NSDateFormatterNoStyle; } // 將轉換后得到的日期字符串設置為 dateLabel 的標題 self.dateLabel.text = [dateFormatter stringFromDate:item.createDate]; } @end
當點擊 UINavigationBar 對象上的返回按鈕時,需要進行的操作
#import "JXItemsViewController.h" #import "JXItem.h" #import "JXItemStore.h" #import "JXDetailViewController.h" @interface JXItemsViewController () /** 頭部視圖 */ @property (nonatomic,weak) UIView * headerView; /** 編輯按鈕 */ @property (nonatomic,strong) UIButton * editButton; /** 增加按鈕 */ @property (nonatomic,strong) UIButton * addButton; @end @implementation JXItemsViewController - (instancetype)init { // 調用父類的指定初始化方法 self = [super initWithStyle:UITableViewStylePlain]; if (self) { for (NSInteger i=0; i<5; i++) { [[JXItemStore sharedStore] createItem]; } } return self; } - (instancetype)initWithStyle:(UITableViewStyle)style { return [self init]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView reloadData]; } - (void)viewDidLoad { [super viewDidLoad]; // 向控制器注冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; // 加載頭視圖 [self headerView]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[JXItemStore sharedStore] allItem] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 創建 UITableViewCell 對象,風格使用默認風格 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath]; // 獲取 allItem 的第 n 個 JXItem 對象 // 然后將該 JXItem 對象的描述信息賦值給 UITableViewCell 對象的 textLabel // 這里的 n 是該 UITableViewCell 對象所對應的表格索引 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; cell.textLabel.text = [item description]; return cell; } /** * 刪除行 * * @param tableView 對象 * @param editingStyle 操作 * @param indexPath 操作的行數 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // 如果tableView請求的是刪除對象 if (editingStyle == UITableViewCellEditingStyleDelete) { // 取出需要刪除的對象 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; // 刪除對象 [[JXItemStore sharedStore] removeItem:item]; // 刷新表格 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } /** * 移動行 * * @param tableView 對象 * @param sourceIndexPath 需要移動的行 * @param destinationIndexPath 目標行 */ - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { [[JXItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row]; } #pragma mark - UITalbeViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { JXDetailViewController * detailController = [[JXDetailViewController alloc] init]; NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * selectedItem = items[indexPath.row]; // 將選中的JXItem 對象賦給 DetailViewController 對象 detailController.item = selectedItem; // 將新創建的控制器壓入到導航控制器對象棧中 [self.navigationController pushViewController:detailController animated:YES]; } #pragma mark - 懶加載 - (UIView *)headerView{ if (_headerView == nil) { UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; // 設置頭部視圖 self.tableView.tableHeaderView = headerView; headerView.backgroundColor = [UIColor cyanColor]; [headerView addSubview:self.editButton]; [headerView addSubview:self.addButton]; _headerView = headerView; } return _headerView; } - (UIButton *)editButton{ if (_editButton == nil) { _editButton = [UIButton buttonWithType:UIButtonTypeCustom]; _editButton.frame = CGRectMake(0, 0, self.view.bounds.size.width / 2, 50); [_editButton setTitle:@"Edit" forState:UIControlStateNormal]; _editButton.backgroundColor = [UIColor greenColor]; [_editButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [_editButton addTarget:self action:@selector(editClick:) forControlEvents:UIControlEventTouchDown]; } return _editButton; } - (UIButton *)addButton{ if (_addButton == nil) { UIButton * addButton = [UIButton buttonWithType:UIButtonTypeCustom]; addButton.frame = CGRectMake(self.view.bounds.size.width / 2, 0, self.view.bounds.size.width / 2, 50); [addButton setTitle:@"Add" forState:UIControlStateNormal]; addButton.backgroundColor = [UIColor blueColor]; [addButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [addButton addTarget:self action:@selector(addClick:) forControlEvents:UIControlEventTouchDown]; _addButton = addButton; } return _addButton; } #pragma mark - 點擊事件 - (void)editClick:(UIButton *)sender { if (self.isEditing) { // 如果是編輯狀態,取消編輯 // 更改文字 [sender setTitle:@"Edit" forState:UIControlStateNormal]; // 取消編輯 [self setEditing:NO animated:YES]; } else { // 更改文字 [sender setTitle:@"Done" forState:UIControlStateNormal]; // 開始編輯 [self setEditing:YES animated:YES]; } } /** * 添加表格時,必須保證 UITableView 對象當前顯示的行數與數據源的提供的行數相同。 * 所以,在添加之前,必須先創建一個新的 JXItem 對象並加入到 JXItemStore 中 * * @param sender 按鈕 */ - (void)addClick:(UIButton *)sender { // 創建新的 JXItem 對象,並加入到 JXItemStore 中 JXItem * newItem = [[JXItemStore sharedStore] createItem]; // 獲取新的對象在 allItem 數組中的索引 NSInteger lastRow = [[[JXItemStore sharedStore] allItem] indexOfObject:newItem]; NSIndexPath * indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0]; // 將新航插入 UITableView 對象 [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; } @end
構建並運行。即可更改信息。
- UINavigationBar
UINavigationBar 目前沒有顯示任何內容,下面我們設置一些顯示內容。
UIViewController 對象有一個名為 navigationItem 的屬性,類型為 UINavigationItem 。和 UINavigationBar 不同,UINavigaitonItem 不是 UIView 的子類,不能再屏幕上顯示。UINavigationItem 對象的作用是為 UINavigationBar 對象提供繪圖所需的內容。當某個 UIViewController 對象成為 UINavigationController 的棧頂控制器對象時,UINavigationBar 對象就會訪問該 UIViewController 對象的 navigationItem 。
UINavigationItem 對象默認是空,設置方式為
#import "JXItemsViewController.h" #import "JXItem.h" #import "JXItemStore.h" #import "JXDetailViewController.h" @interface JXItemsViewController () /** 頭部視圖 */ @property (nonatomic,weak) UIView * headerView; /** 編輯按鈕 */ @property (nonatomic,strong) UIButton * editButton; /** 增加按鈕 */ @property (nonatomic,strong) UIButton * addButton; @end @implementation JXItemsViewController - (instancetype)init { // 調用父類的指定初始化方法 self = [super initWithStyle:UITableViewStylePlain]; if (self) { UINavigationItem * navItem = self.navigationItem; navItem.title = @"JXHomepwner"; for (NSInteger i=0; i<5; i++) { [[JXItemStore sharedStore] createItem]; } } return self; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView reloadData]; } - (void)viewDidLoad { [super viewDidLoad]; // 向控制器注冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; // 加載頭視圖 [self headerView]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[JXItemStore sharedStore] allItem] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 創建 UITableViewCell 對象,風格使用默認風格 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath]; // 獲取 allItem 的第 n 個 JXItem 對象 // 然后將該 JXItem 對象的描述信息賦值給 UITableViewCell 對象的 textLabel // 這里的 n 是該 UITableViewCell 對象所對應的表格索引 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; cell.textLabel.text = [item description]; return cell; } /** * 刪除行 * * @param tableView 對象 * @param editingStyle 操作 * @param indexPath 操作的行數 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // 如果tableView請求的是刪除對象 if (editingStyle == UITableViewCellEditingStyleDelete) { // 取出需要刪除的對象 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; // 刪除對象 [[JXItemStore sharedStore] removeItem:item]; // 刷新表格 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } /** * 移動行 * * @param tableView 對象 * @param sourceIndexPath 需要移動的行 * @param destinationIndexPath 目標行 */ - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { [[JXItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row]; } #pragma mark - UITalbeViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { JXDetailViewController * detailController = [[JXDetailViewController alloc] init]; NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * selectedItem = items[indexPath.row]; // 將選中的JXItem 對象賦給 DetailViewController 對象 detailController.item = selectedItem; // 將新創建的控制器壓入到導航控制器對象棧中 [self.navigationController pushViewController:detailController animated:YES]; } #pragma mark - 懶加載 - (UIView *)headerView{ if (_headerView == nil) { UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; // 設置頭部視圖 self.tableView.tableHeaderView = headerView; headerView.backgroundColor = [UIColor cyanColor]; [headerView addSubview:self.editButton]; [headerView addSubview:self.addButton]; _headerView = headerView; } return _headerView; } - (UIButton *)editButton{ if (_editButton == nil) { _editButton = [UIButton buttonWithType:UIButtonTypeCustom]; _editButton.frame = CGRectMake(0, 0, self.view.bounds.size.width / 2, 50); [_editButton setTitle:@"Edit" forState:UIControlStateNormal]; _editButton.backgroundColor = [UIColor greenColor]; [_editButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [_editButton addTarget:self action:@selector(editClick:) forControlEvents:UIControlEventTouchDown]; } return _editButton; } - (UIButton *)addButton{ if (_addButton == nil) { UIButton * addButton = [UIButton buttonWithType:UIButtonTypeCustom]; addButton.frame = CGRectMake(self.view.bounds.size.width / 2, 0, self.view.bounds.size.width / 2, 50); [addButton setTitle:@"Add" forState:UIControlStateNormal]; addButton.backgroundColor = [UIColor blueColor]; [addButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [addButton addTarget:self action:@selector(addClick:) forControlEvents:UIControlEventTouchDown]; _addButton = addButton; } return _addButton; } #pragma mark - 點擊事件 - (void)editClick:(UIButton *)sender { if (self.isEditing) { // 如果是編輯狀態,取消編輯 // 更改文字 [sender setTitle:@"Edit" forState:UIControlStateNormal]; // 取消編輯 [self setEditing:NO animated:YES]; } else { // 更改文字 [sender setTitle:@"Done" forState:UIControlStateNormal]; // 開始編輯 [self setEditing:YES animated:YES]; } } /** * 添加表格時,必須保證 UITableView 對象當前顯示的行數與數據源的提供的行數相同。 * 所以,在添加之前,必須先創建一個新的 JXItem 對象並加入到 JXItemStore 中 * * @param sender 按鈕 */ - (void)addClick:(UIButton *)sender { // 創建新的 JXItem 對象,並加入到 JXItemStore 中 JXItem * newItem = [[JXItemStore sharedStore] createItem]; // 獲取新的對象在 allItem 數組中的索引 NSInteger lastRow = [[[JXItemStore sharedStore] allItem] indexOfObject:newItem]; NSIndexPath * indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0]; // 將新航插入 UITableView 對象 [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; } @end
構建並運行;UINavigationBar 對象會顯示我們設置的標題。添加一個新的控制器(選中表格行),UINavigationBar 對象的標題會消失,所以下面我們要繼續設置。
#import "JXDetailViewController.h" #import "JXItem.h" @interface JXDetailViewController () @property (weak, nonatomic) IBOutlet UITextField *nameField; @property (weak, nonatomic) IBOutlet UITextField *seriaNumberField; @property (weak, nonatomic) IBOutlet UITextField *valueField; @property (weak, nonatomic) IBOutlet UILabel *dateLabel; @end @implementation JXDetailViewController - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // 取消當前的第一響應對象 [self.view endEditing:YES]; // 將修改保存到 JXItem JXItem * item = self.item; item.itemName = self.nameField.text; item.serialnumber = self.seriaNumberField.text; item.valueInDollars = [self.valueField.text integerValue]; } - (void)viewDidLoad { [super viewDidLoad]; JXItem * item = self.item; self.nameField.text = item.itemName; self.seriaNumberField.text = item.itemName; self.valueField.text = [NSString stringWithFormat:@"%ld",item.valueInDollars]; // 創建 NSDdateFoemateter 對象,用於將 NSDate 對象轉換成簡單的日期字符串 static NSDateFormatter * dateFormatter = nil; if (!dateFormatter) { dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateStyle = NSDateFormatterMediumStyle; dateFormatter.timeStyle = NSDateFormatterNoStyle; } // 將轉換后得到的日期字符串設置為 dateLabel 的標題 self.dateLabel.text = [dateFormatter stringFromDate:item.createDate]; } - (void)setItem:(JXItem *)item { _item = item; self.navigationItem.title = _item.itemName; } @end
UINavigationItem 對象除了可以設置標題字符串外,還可以設置若干其他的界面屬性。包括 : leftBarButtonItem 、 rightBarButtonItem 和 titleView 。其中 leftBarButtonItem 和 rightBarButtonItem 都是指向 UIBarButtonItem 對象的指針,該對象包含顯示某種特殊按鈕所需要的信息,這種按鈕只能在 UINavigationBar 對象或 UIToolbar 對象中使用。
類似於 UINavigationItem ,UIBarButtonItem 也不是 UIView 的子類。UINavigationItem 對象封裝了一些設置信息,以便於 UINavigationBar 在運行時可以正確顯示該對象。同樣,UIBarButtonItem 對象封裝了關於如何在 UINavigationBar 顯示單個按鈕的信息,UINavigationBar 對象會根據 UIBarButtonItem 對象中的信息顯示相應的按鈕。(UIToolbar 與 UINavigationBar 一樣,也是通過 UIBarButtonItem 對象來顯示按鈕的。)
除了 leftBarButtonItem 和 rightBarButtonItem ,UINavigationItem 對象的第三個界面屬性 titleView 。UINavigationBar 對象包含兩種標題顯示模式。第一種是顯示一個簡單的字符串。第二種模式是顯示一個視圖。兩種模式不能共存。如果需要在 UINavigationBar 對象正中顯示一個復雜界面,就可以先創建擁有自定義視圖(例如 UIButton 對象、UISlider 對象、UIImageView 對象等)的視圖控制器,然后為該對象的 titleView 賦值,並指向這個自定義視圖。
下面讓 UINavigationBar 對象顯示一個按鈕:當 JXItemsViewController 對象位於棧頂時,在 UINavigationBar 對象的右端顯示一個按鈕。當用戶點擊這個按鈕時,為UITableView 對象增加一個新的表格。
為了能在用戶點擊 UINavigationBar 對象中的按鈕時觸發指定的方法,必須為相應的 UIBarButtonItem 對象設置目標-動作對。
#import "JXItemsViewController.h" #import "JXItem.h" #import "JXItemStore.h" #import "JXDetailViewController.h" @interface JXItemsViewController () /** 頭部視圖 */ @property (nonatomic,weak) UIView * headerView; /** 編輯按鈕 */ @property (nonatomic,strong) UIButton * editButton; /** 增加按鈕 */ @property (nonatomic,strong) UIButton * addButton; @end @implementation JXItemsViewController - (instancetype)init { // 調用父類的指定初始化方法 self = [super initWithStyle:UITableViewStylePlain]; if (self) { UINavigationItem * navItem = self.navigationItem; navItem.title = @"JXHomepwner"; // 創建新的 UIBarButtonItem 對象 // 將其目標對象設置為當前對象,將其多做方法設置為指定方法 UIBarButtonItem * bdi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addClick:)]; // 為 UINavigationItem 對象的 rightBarButtonItem 屬性賦值 // 指向新創建的 UIBarButtonItem 對象 navItem.rightBarButtonItem = bdi; for (NSInteger i=0; i<5; i++) { [[JXItemStore sharedStore] createItem]; } } return self; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView reloadData]; } - (void)viewDidLoad { [super viewDidLoad]; // 向控制器注冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; // 加載頭視圖 [self headerView]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[JXItemStore sharedStore] allItem] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 創建 UITableViewCell 對象,風格使用默認風格 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath]; // 獲取 allItem 的第 n 個 JXItem 對象 // 然后將該 JXItem 對象的描述信息賦值給 UITableViewCell 對象的 textLabel // 這里的 n 是該 UITableViewCell 對象所對應的表格索引 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; cell.textLabel.text = [item description]; return cell; } /** * 刪除行 * * @param tableView 對象 * @param editingStyle 操作 * @param indexPath 操作的行數 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // 如果tableView請求的是刪除對象 if (editingStyle == UITableViewCellEditingStyleDelete) { // 取出需要刪除的對象 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; // 刪除對象 [[JXItemStore sharedStore] removeItem:item]; // 刷新表格 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } /** * 移動行 * * @param tableView 對象 * @param sourceIndexPath 需要移動的行 * @param destinationIndexPath 目標行 */ - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { [[JXItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row]; } #pragma mark - UITalbeViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { JXDetailViewController * detailController = [[JXDetailViewController alloc] init]; NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * selectedItem = items[indexPath.row]; // 將選中的JXItem 對象賦給 DetailViewController 對象 detailController.item = selectedItem; // 將新創建的控制器壓入到導航控制器對象棧中 [self.navigationController pushViewController:detailController animated:YES]; } #pragma mark - 懶加載 - (UIView *)headerView{ if (_headerView == nil) { UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; // 設置頭部視圖 self.tableView.tableHeaderView = headerView; headerView.backgroundColor = [UIColor cyanColor]; [headerView addSubview:self.editButton]; [headerView addSubview:self.addButton]; _headerView = headerView; } return _headerView; } - (UIButton *)editButton{ if (_editButton == nil) { _editButton = [UIButton buttonWithType:UIButtonTypeCustom]; _editButton.frame = CGRectMake(0, 0, self.view.bounds.size.width / 2, 50); [_editButton setTitle:@"Edit" forState:UIControlStateNormal]; _editButton.backgroundColor = [UIColor greenColor]; [_editButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [_editButton addTarget:self action:@selector(editClick:) forControlEvents:UIControlEventTouchDown]; } return _editButton; } - (UIButton *)addButton{ if (_addButton == nil) { UIButton * addButton = [UIButton buttonWithType:UIButtonTypeCustom]; addButton.frame = CGRectMake(self.view.bounds.size.width / 2, 0, self.view.bounds.size.width / 2, 50); [addButton setTitle:@"Add" forState:UIControlStateNormal]; addButton.backgroundColor = [UIColor blueColor]; [addButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [addButton addTarget:self action:@selector(addClick:) forControlEvents:UIControlEventTouchDown]; _addButton = addButton; } return _addButton; } #pragma mark - 點擊事件 - (void)editClick:(UIButton *)sender { if (self.isEditing) { // 如果是編輯狀態,取消編輯 // 更改文字 [sender setTitle:@"Edit" forState:UIControlStateNormal]; // 取消編輯 [self setEditing:NO animated:YES]; } else { // 更改文字 [sender setTitle:@"Done" forState:UIControlStateNormal]; // 開始編輯 [self setEditing:YES animated:YES]; } } /** * 添加表格時,必須保證 UITableView 對象當前顯示的行數與數據源的提供的行數相同。 * 所以,在添加之前,必須先創建一個新的 JXItem 對象並加入到 JXItemStore 中 * * @param sender 按鈕 */ - (void)addClick:(UIButton *)sender { // 創建新的 JXItem 對象,並加入到 JXItemStore 中 JXItem * newItem = [[JXItemStore sharedStore] createItem]; // 獲取新的對象在 allItem 數組中的索引 NSInteger lastRow = [[[JXItemStore sharedStore] allItem] indexOfObject:newItem]; NSIndexPath * indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0]; // 將新航插入 UITableView 對象 [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; } @end
接着我么設置天極愛一個編輯按鈕,用來替換 Edit 按鈕。
#import "JXItemsViewController.h" #import "JXItem.h" #import "JXItemStore.h" #import "JXDetailViewController.h" @interface JXItemsViewController () /** 頭部視圖 */ @property (nonatomic,weak) UIView * headerView; /** 編輯按鈕 */ @property (nonatomic,strong) UIButton * editButton; /** 增加按鈕 */ @property (nonatomic,strong) UIButton * addButton; @end @implementation JXItemsViewController - (instancetype)init { // 調用父類的指定初始化方法 self = [super initWithStyle:UITableViewStylePlain]; if (self) { UINavigationItem * navItem = self.navigationItem; navItem.title = @"JXHomepwner"; // 創建新的 UIBarButtonItem 對象 // 將其目標對象設置為當前對象,將其多做方法設置為指定方法 UIBarButtonItem * bdi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addClick:)]; // 為 UINavigationItem 對象的 rightBarButtonItem 屬性賦值 // 指向新創建的 UIBarButtonItem 對象 navItem.rightBarButtonItem = bdi; UIBarButtonItem * edit = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editClick:)]; navItem.leftBarButtonItem = edit; for (NSInteger i=0; i<5; i++) { [[JXItemStore sharedStore] createItem]; } } return self; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView reloadData]; } - (void)viewDidLoad { [super viewDidLoad]; // 向控制器注冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"]; // 加載頭視圖 [self headerView]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[JXItemStore sharedStore] allItem] count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 創建 UITableViewCell 對象,風格使用默認風格 UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forIndexPath:indexPath]; // 獲取 allItem 的第 n 個 JXItem 對象 // 然后將該 JXItem 對象的描述信息賦值給 UITableViewCell 對象的 textLabel // 這里的 n 是該 UITableViewCell 對象所對應的表格索引 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; cell.textLabel.text = [item description]; return cell; } /** * 刪除行 * * @param tableView 對象 * @param editingStyle 操作 * @param indexPath 操作的行數 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { // 如果tableView請求的是刪除對象 if (editingStyle == UITableViewCellEditingStyleDelete) { // 取出需要刪除的對象 NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * item = items[indexPath.row]; // 刪除對象 [[JXItemStore sharedStore] removeItem:item]; // 刷新表格 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } /** * 移動行 * * @param tableView 對象 * @param sourceIndexPath 需要移動的行 * @param destinationIndexPath 目標行 */ - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { [[JXItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row]; } #pragma mark - UITalbeViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { JXDetailViewController * detailController = [[JXDetailViewController alloc] init]; NSArray * items = [[JXItemStore sharedStore] allItem]; JXItem * selectedItem = items[indexPath.row]; // 將選中的JXItem 對象賦給 DetailViewController 對象 detailController.item = selectedItem; // 將新創建的控制器壓入到導航控制器對象棧中 [self.navigationController pushViewController:detailController animated:YES]; } #pragma mark - 懶加載 - (UIView *)headerView{ if (_headerView == nil) { UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; // 設置頭部視圖 self.tableView.tableHeaderView = headerView; headerView.backgroundColor = [UIColor cyanColor]; [headerView addSubview:self.editButton]; [headerView addSubview:self.addButton]; _headerView = headerView; } return _headerView; } - (UIButton *)editButton{ if (_editButton == nil) { _editButton = [UIButton buttonWithType:UIButtonTypeCustom]; _editButton.frame = CGRectMake(0, 0, self.view.bounds.size.width / 2, 50); [_editButton setTitle:@"Edit" forState:UIControlStateNormal]; _editButton.backgroundColor = [UIColor greenColor]; [_editButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [_editButton addTarget:self action:@selector(editClick:) forControlEvents:UIControlEventTouchDown]; } return _editButton; } - (UIButton *)addButton{ if (_addButton == nil) { UIButton * addButton = [UIButton buttonWithType:UIButtonTypeCustom]; addButton.frame = CGRectMake(self.view.bounds.size.width / 2, 0, self.view.bounds.size.width / 2, 50); [addButton setTitle:@"Add" forState:UIControlStateNormal]; addButton.backgroundColor = [UIColor blueColor]; [addButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [addButton addTarget:self action:@selector(addClick:) forControlEvents:UIControlEventTouchDown]; _addButton = addButton; } return _addButton; } #pragma mark - 點擊事件 - (void)editClick:(UIButton *)sender {
- (void)editClick:(UIBarButtonItem *)sender { if (self.isEditing) { // 如果是編輯狀態,取消編輯 // 更改文字 [sender setTitle:@"Edit" forState:UIControlStateNormal]; // 取消編輯 [self setEditing:NO animated:YES]; } else { // 更改文字 [sender setTitle:@"Done" forState:UIControlStateNormal]; // 開始編輯 [self setEditing:YES animated:YES]; } } /** * 添加表格時,必須保證 UITableView 對象當前顯示的行數與數據源的提供的行數相同。 * 所以,在添加之前,必須先創建一個新的 JXItem 對象並加入到 JXItemStore 中 * * @param sender 按鈕 */ - (void)addClick:(UIButton *)sender { // 創建新的 JXItem 對象,並加入到 JXItemStore 中 JXItem * newItem = [[JXItemStore sharedStore] createItem]; // 獲取新的對象在 allItem 數組中的索引 NSInteger lastRow = [[[JXItemStore sharedStore] allItem] indexOfObject:newItem]; NSIndexPath * indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0]; // 將新航插入 UITableView 對象 [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; } @end
構建並運行