標籤:ios tableview
最終:
Girl.h
//// Girl.h// 12_tableView的增刪改//// Created by beyond on 14-7-27.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import <Foundation/Foundation.h>@interface Girl : NSObject// UI控制項用weak,字串用copy,其他對象用strong// 頭像圖片名@property(nonatomic,copy)NSString *headImgName;// 姓名@property(nonatomic,copy)NSString *name;// 判詞@property(nonatomic,copy)NSString *verdict;// 提供一個類方法,即建構函式,返回封裝好資料的對象(返回id亦可)+ (Girl *)girlNamed:(NSString *)name headImgName:(NSString*)headImgName verdict:(NSString *)verdict;// 類方法,字典 轉 對象 類似javaBean一次性填充+ (Girl *)girlWithDict:(NSDictionary *)dict;// 對象方法,設定對象的屬性後,返回對象- (Girl *)initWithDict:(NSDictionary *)dict;@end
Girl.m
//// Girl.m// 12_tableView的增刪改//// Created by beyond on 14-7-27.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import "Girl.h"@implementation Girl// 提供一個類方法,即建構函式,返回封裝好資料的對象(返回id亦可)+(Girl *)girlNamed:(NSString *)name headImgName:(NSString *)headImgName verdict:(NSString *)verdict{ Girl *girl = [[Girl alloc]init]; girl.name = name; girl.headImgName = headImgName; girl.verdict = verdict; return girl;}// 類方法,字典 轉 對象 類似javaBean一次性填充+ (Girl *)girlWithDict:(NSDictionary *)dict{ // 只是調用對象的initWithDict方法,之所以用self是為了對子類進行相容 return [[self alloc]initWithDict:dict];}// 對象方法,設定對象的屬性後,返回對象- (Girl *)initWithDict:(NSDictionary *)dict{ // 先調用父類NSObject的init方法 if (self = [super init]) { // 設定對象自己的屬性 self.name = dict[@"name"] ; self.headImgName = dict[@"headImg"] ; self.verdict = dict[@"verdict"]; } // 返回填充好的對象 return self;}@end
BeyondViewController.h
//// BeyondViewController.h// 12_tableView的增刪改//// Created by beyond on 14-7-27.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import <UIKit/UIKit.h>@interface BeyondViewController : UIViewController// 標題@property (weak, nonatomic) IBOutlet UILabel *titleStatus;// tableView@property (weak, nonatomic) IBOutlet UITableView *tableView;// 清空按鈕@property (weak, nonatomic) IBOutlet UIBarButtonItem *trashBtn;// 全選 反選按鈕@property (weak, nonatomic) IBOutlet UIBarButtonItem *checkAllBtn;// 清空- (IBAction)trashBtnClick:(UIBarButtonItem *)sender;// 全選 or 反選- (IBAction)checkAll:(UIBarButtonItem *)sender;@end
BeyondViewController.m
//// BeyondViewController.m// 12_tableView的增刪改//// Created by beyond on 14-7-27.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import "BeyondViewController.h"#import "Girl.h"@interface BeyondViewController ()<UITableViewDataSource,UITableViewDelegate>{ // 從plist檔案中載入的所有girls,返回字典數組 NSArray *_arrayWithDict; // 所有的對象數組 NSMutableArray *_girls; // 被勾選的行的對應該的模型數組 // 不用數組也行,只要在模型中增加一個屬性:記錄是否被選中 NSMutableArray *_checkedGirls;}@end@implementation BeyondViewController- (void)viewDidLoad{ [super viewDidLoad]; // 所有的對象數組 _girls = [NSMutableArray array]; // 被勾選的行的數組 _checkedGirls = [NSMutableArray array]; // 調用自訂方法,載入plist檔案 [self loadPlist]; }// 自訂方法,載入plist檔案- (void)loadPlist{ // sg_bundle模板代碼,1,獲得.app主要的包;2,返回主要的包中某個檔案的fullPath全路徑 NSBundle *mainBundle = [NSBundle mainBundle]; NSString *fullPath = [mainBundle pathForResource:@"girls.plist" ofType:nil]; // 從plist檔案中根據全路徑,返回字典數組 _arrayWithDict = [NSArray arrayWithContentsOfFile:fullPath]; // 再調用自訂方法,將字典數組,轉換成對象數組 [self dictArrayToModel]; }// 自訂方法,將字典數組,轉換成對象數組- (void)dictArrayToModel{ // 字典數組 _arrayWithDict // 方式1:for in,這種情況下,控制器知道的東西太多了,如果模型增加屬性,還要改控制器中的代碼 /* for (NSDictionary *dict in _arrayWithDict) { Girl *girl = [Girl girlNamed:dict[@"name"] headImgName:dict[@"headImg"] verdict:dict[@"verdict"]]; [_girls addObject:girl]; } */ // 方式2:類方法返回對象,參數只要一個字典數組即可 for (NSDictionary *dict in _arrayWithDict) { // 參數只要字典,這樣一來,控制器就不用知道太多東西了 // Girl *girl = [[Girl alloc]initWithDict:dict]; Girl *girl = [Girl girlWithDict:dict]; [_girls addObject:girl]; }}// 資料來源方法,預設是單組,共有多少行 (每次重新整理資料都會調用此行)- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ // 返回數組中對應的字典的長度 return _girls.count;}// 資料來源方法,每一組的每一行應該顯示怎麼的介面(含封裝的資料),重點!!!必須實現否則,Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *cellID = @"Beyond"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; if (cell == nil) { // 如果池中沒取到,則重建一個cell /* cell的4種樣式: 1,default 左圖右文字 2,subtitle 左圖 上文字大 下文字小 3,value 1 左圖 左文字大 右文字小 3,value 2 噁心 左文字小 右文字大 */ cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID]; } // 設定cell中獨一無二的內容 Girl *girl = _girls[indexPath.row]; cell.textLabel.text = girl.name; cell.imageView.image = [UIImage imageNamed:girl.headImgName]; cell.detailTextLabel.text = girl.verdict; // 判斷,如果模型存在於checkedArray中,則標記為checked if ([_checkedGirls containsObject:girl]) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } else { cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } // 返回cell return cell;}// 代理方法,每一行的高度- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 83;}// 代理方法,點擊行,新版本 MVC- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ // 取消tableView點擊後背景高亮的藍色 [tableView deselectRowAtIndexPath:indexPath animated:YES]; // 獲得被點擊的行的對應的資料模型 Girl *girl = [_girls objectAtIndex:indexPath.row]; // 判斷,若沒被勾選過,則勾選,否則取消勾選 // 方式2:只修改模型,不動cell,讓tableView reload資料即可,符合MVC~ if ([_checkedGirls containsObject:girl]) { // 取消勾選,從勾選數組中移除,然後再次reloadData [_checkedGirls removeObject:girl]; } else { // 加入到選中數組中,然後再次reloadData! [_checkedGirls addObject:girl]; } // 再次reloadData [_tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; // 最後調用自訂方法,檢查trash按鈕的可用性,以及標題的變化 [self statusCheck]; }// 代理方法,點擊行----舊版本- (void)oldVersionTableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ // 取消tableView點擊後背景高亮的藍色 [tableView deselectRowAtIndexPath:indexPath animated:YES]; // 獲得被點擊的行 UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; // 獲得被點擊的行的對應的資料模型 Girl *girl = [_girls objectAtIndex:indexPath.row]; // 判斷,若沒被勾選過,則勾選,否則取消勾選 // 方式1:手動設定cell的樣式,但是,這不符合MVC思想~ /* if (cell.accessoryType != UITableViewCellAccessoryCheckmark) { // 勾選上,同時要加入到數組中,記住! cell.accessoryType = UITableViewCellAccessoryCheckmark; [_checkedGirls addObject:girl]; } else { // 取消勾選,同時要移除 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; [_checkedGirls removeObject:girl]; } */ // 方式2:只修改模型,不動cell,讓tableView reload資料即可,符合MVC~ if (cell.accessoryType != UITableViewCellAccessoryCheckmark) { // 加入到選中數組中,然後再次reloadData! [_checkedGirls addObject:girl]; [_tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else { // 取消勾選,從勾選數組中移除,然後再次reloadData [_checkedGirls removeObject:girl]; [_tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } // 最後調用自訂方法,檢查trash按鈕的可用性,以及標題的變化 [self statusCheck];}// 當點擊了toolBar中的trash 按鈕時調用- (IBAction)trashBtnClick:(UIBarButtonItem *)sender { // 可變數組,成員是所有的勾選的行組成的indexPath NSMutableArray *indexPaths = [NSMutableArray array]; // 遍曆checkedGirls,得到勾選的行號們,並封裝成一個個indexPath,然後添加到indexPaths數組,目的是後面tableView刪除行方法中用到 for (Girl *girl in _checkedGirls) { // 勾選的行的行號 int row = [_girls indexOfObject:girl]; // 封裝成IndexPath NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0]; // 添加到IndexPaths數組 [indexPaths addObject:indexPath]; } // 先修改模型(從所有的對象數組中刪除 勾選的對象們,並且清空勾選的對象數組),最後再deleteRowsAtIndexPaths(注意reload前提是資料來源個數不能增加或減少) [_girls removeObjectsInArray:_checkedGirls]; [_checkedGirls removeAllObjects]; // deleteRows刪除行之後,剩餘的行數,必須與資料來源的行數相等,意思就是:資料來源中也要刪除同樣多的行的資料,才可以調用deleteRows方法 [_tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight]; // 最後調用自訂方法,檢查trash按鈕的可用性,以及標題的變化 [self statusCheck];}// 最後調用自訂方法,檢查trash按鈕的可用性,以及標題的變化- (void)statusCheck{ // 如果表格沒有資料了,則直接禁用掉全選按鈕 if (_girls.count == 0) { _checkAllBtn.enabled = NO; } // 設定顯示checked的行數 if (_checkedGirls.count != 0) { // 如果沒有被選中的行,則禁用 刪除按鈕 _trashBtn.enabled = YES; // 顯示數字(預設bar button item中的文本是不可更改的,所以改成label標籤) NSString *titleStatus = [NSString stringWithFormat:@"紅樓夢(%d)",_checkedGirls.count]; _titleStatus.text = titleStatus; } else { _trashBtn.enabled = NO; _titleStatus.text = @"紅樓夢"; }}// toolBar最右邊的 全選 or 反選按鈕- (IBAction)checkAll:(UIBarButtonItem *)sender { if (_girls.count == _checkedGirls.count) { // 取消全選 先修改模型,再reload [_checkedGirls removeAllObjects]; [_tableView reloadData]; } else { // 全選 先修改模型,再reload // 必須先清空checked數組,再全部添加 [_checkedGirls removeAllObjects]; [_checkedGirls addObjectsFromArray:_girls]; [_tableView reloadData]; } // 調用自訂方法 修改檢測狀態 [self statusCheck]; }@end
屬性列表檔案girls.plist
main.storyboard
因為bar button item的文字不可更改, 遂換成label,
label不接收點擊事件,所以可以向後傳遞給button處理點擊事件