UITableViewhtml
基本介紹api
UITableView有兩種風格:UITableViewStylePlain和UITableViewStyleGrouped。這二者操做起來其實並無本質區別,只是後者按分組樣式顯示前者按照普通樣式顯示而已。數組
在UITableView中數據只有行的概念,並無列的概念,由於在手機操做系統中顯示多列是不利於操做的。UITableView中每行數據都是一個UITableViewCell,在這個控件中爲了顯示更多的信息,iOS已經在其內部設置好了多個子控件以供開發者使用。若是咱們查看UITableViewCell的聲明文件能夠發如今內部有一個UIView控件(contentView,做爲其餘元素的父控件)、兩個UILable控件(textLabel、detailTextLabel)、一個UIImage控件(imageView),分別用於容器、顯示內容、詳情和圖片。使用效果相似於微信、QQ信息列表。緩存
固然,這些子控件並不必定要所有使用,具體操做時能夠經過UITableViewCellStyle進行設置,具體每一個枚舉表示的意思已經在代碼中進行了註釋:性能優化
typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault, // 左側顯示textLabel(不顯示detailTextLabel),imageView可選(顯示在最左邊) UITableViewCellStyleValue1, // 左側顯示textLabel、右側顯示detailTextLabel(默認藍色),imageView可選(顯示在最左邊) UITableViewCellStyleValue2, // 左側依次顯示textLabel(默認藍色)和detailTextLabel,imageView可選(顯示在最左邊) UITableViewCellStyleSubtitle // 左上方顯示textLabel,左下方顯示detailTextLabel(默認灰色),imageView可選(顯示在最左邊) };
數據源微信
因爲iOS是遵循MVC模式設計的,不少操做都是經過代理和外界溝通的,但對於數據源控件除了代理還有一個數據源屬性,經過它和外界進行數據交互。 對於UITableView設置完dataSource後須要實現UITableViewDataSource協議,在這個協議中定義了多種 數據操做方法,下面經過建立一個簡單的聯繫人管理進行演示:app
首先咱們須要建立一個聯繫人模型KCContact(通信錄)ide
KCContact.h函數
#import <Foundation/Foundation.h> //聯繫人模型 @interface KCContact : NSObject #pragma mark 姓 @property (nonatomic,copy) NSString *firstName; #pragma mark 名 @property (nonatomic,copy) NSString *lastName; #pragma mark 手機號碼 @property (nonatomic,copy) NSString *phoneNumber; #pragma mark 帶參數的構造函數 -(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)laseName andPhoneNumber:(NSString *)phoneNumber; #pragma mark 取得姓名 -(NSString *)getName; #pragma mark 帶參數的靜態對象初始化方法 +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)laseName andPhoneNumber:(NSString *)phoneNumber; @end
KCContact.m工具
#import "KCContact.h" @implementation KCContact //獲得數據源的姓和名的方法 -(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)laseName andPhoneNumber:(NSString *)phoneNumber{ if (self = [super init]) { self.firstName = firstName; self.lastName = laseName; self.phoneNumber = phoneNumber; } return self; } //拼接 姓+名 的方法 -(NSString *)getName{ return [NSString stringWithFormat:@"%@%@", _firstName,_lastName]; } +(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)laseName andPhoneNumber:(NSString *)phoneNumber{ KCContact *contact1 = [[KCContact alloc]initWithFirstName:firstName andLastName:laseName andPhoneNumber:phoneNumber]; return contact1; } @end
聯繫人分組模型(好比姓劉的,姓張的都各自是一組)KCContactGroup
KCContactGroup.h
#import <Foundation/Foundation.h> #import "KCContact.h" //聯繫人分組模型 @interface KCContactGroup : NSObject #pragma mark 組名 @property (nonatomic,copy) NSString *name; #pragma mark 分組描述 @property (nonatomic,copy) NSString *detail; #pragma mark 聯繫人 @property (nonatomic,strong) NSMutableArray *contacts; #pragma mark 帶參數的構造函數 -(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts; #pragma mark 靜態初始化方法 +(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts; @end
KCContactGroup.m
#import "KCContactGroup.h" @implementation KCContactGroup //拿到父類的分組 -(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{ if (self = [super init]) { self.name = name; self.detail = detail; self.contacts = contacts; } return self; } +(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{ KCContactGroup *group1 = [[KCContactGroup alloc]initWithName:name andDetail:detail andContacts:contacts]; return group1; } @end
而後在viewDidLoad方法中建立一些模擬數據同時實現數據源協議方法:
ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController<UIAlertViewDelegate,UITableViewDelegate,UITableViewDataSource> @end
ViewController.m
#import "ViewController.h" #import "KCContact.h" #import "KCContactGroup.h" @interface ViewController (){ UITableView *myTableView;//新建一個UITableView NSMutableArray *contacts;//聯繫人模型 NSIndexPath *selectedIndexPath;//當前選中的組和行 UIToolbar *myToolbar; BOOL isInsert;//記錄是點擊了插入仍是刪除按鈕 } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化數據(!!!很重要) [self initData]; //建立一個分組樣式的UITableView myTableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; //設置數據源,注意必須實現對應的UITableViewDataSource協議 myTableView.dataSource = self; myTableView.delegate = self; [self.view addSubview:myTableView]; /** UITableView和UITableViewCell提供了強大的操做功能,這一節中會重點討論刪除、增長、排序等操做。爲了方便演示咱們仍是在以前的通信錄的基礎上演示,在此以前先來給視圖控制器添加一個工具條,在工具條左側放一個刪除按鈕,右側放一個添加按鈕: */ myToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen]bounds].size.width, 64)]; myToolbar.backgroundColor = [UIColor redColor]; // [self.view addSubview:myToolbar]; //添加刪除按鈕 UIBarButtonItem *removeButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(remove:)]; //間距按鈕 UIBarButtonItem *flexibleButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; //添加按鈕 UIBarButtonItem *addButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add:)]; NSArray *ButtonArray = [NSArray arrayWithObjects:removeButton, flexibleButton, addButton, nil]; // myToolbar.items = ButtonArray; } #pragma mark 加載數據 -(void)initData{ contacts = [[NSMutableArray alloc]init]; KCContact *contact1 = [KCContact initWithFirstName:@"liu" andLastName:@"bo" andPhoneNumber:@"18812345678"]; KCContact *contact2 = [KCContact initWithFirstName:@"wang" andLastName:@"zhaohua" andPhoneNumber:@"18812345678"]; KCContactGroup *group1 = [KCContactGroup initWithName:@"jiaren" andDetail:@"womenshiyijiaren" andContacts:[NSMutableArray arrayWithObjects:contact1, contact2, nil]]; [contacts addObject:group1]; KCContact *contact3 = [KCContact initWithFirstName:@"zhang" andLastName:@"bing" andPhoneNumber:@"12345678900"]; KCContact *contact4 = [KCContact initWithFirstName:@"wu" andLastName:@"wei" andPhoneNumber:@"98765432100"]; KCContact *contact5 = [KCContact initWithFirstName:@"zhang" andLastName:@"san" andPhoneNumber:@"12345612345"]; KCContactGroup *group2 = [KCContactGroup initWithName:@"pengyou" andDetail:@"womenshipengyou" andContacts:[NSMutableArray arrayWithObjects:contact3, contact4, contact5, nil]]; [contacts addObject:group2]; KCContact *contact6 = [KCContact initWithFirstName:@"li" andLastName:@"si" andPhoneNumber:@"12345555555"]; KCContact *contact7 = [KCContact initWithFirstName:@"wang" andLastName:@"wu" andPhoneNumber:@"88888888888"]; KCContactGroup *group3 = [KCContactGroup initWithName:@"tongxue" andDetail:@"womenshitongxue" andContacts:[NSMutableArray arrayWithObjects:contact6, contact7, nil]]; [contacts addObject:group3]; KCContact *contact8 = [KCContact initWithFirstName:@"hi" andLastName:@"pi" andPhoneNumber:@"12345555555"]; KCContact *contact9 = [KCContact initWithFirstName:@"kang" andLastName:@"gu" andPhoneNumber:@"88888888888"]; KCContact *contact10 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact11 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact12 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group4 = [KCContactGroup initWithName:@"qinqi" andDetail:@"womenshiqinqi" andContacts:[NSMutableArray arrayWithObjects:contact8, contact9, contact10, contact11, contact12, nil]]; [contacts addObject:group4]; KCContact *contact13 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact14 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact15 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group5 = [KCContactGroup initWithName:@"tongshi" andDetail:@"womenshitongshi" andContacts:[NSMutableArray arrayWithObjects:contact13, contact14, contact15, nil]]; [contacts addObject:group5]; } #pragma mark - 數據源代理方法 #pragma mark 返回分組數 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ NSLog(@"計算分組數"); return contacts.count; } #pragma mark 返回每組行數 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ NSLog(@"計算每組(組%li)行數",(long)section); KCContactGroup * group1 = contacts[section]; return group1.contacts.count; } #pragma mark 返回每行的單元格 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //NSIndexPath是一個結構體,記錄了組和行的信息 NSLog(@"生成單元格(組:%li 行:%li)",(long)indexPath.section,(long)indexPath.row); KCContactGroup *group = contacts[indexPath.section]; KCContact *contact = group.contacts[indexPath.row]; // //每行cell上面的內容(----------------普通方法建立cell---------------------) // UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil]; // /** // (----------------優化方法建立cell---------------------) // * 優化UITableView,這時咱們不是在滾動到指定位置後更改滾動的位置而是要將當前沒有顯示的Cell從新顯示在將要顯示的Cell的位置而後更新其內容。緣由就是UITableView中的Cell結構佈局多是不一樣的,經過從新定位是不可取的,而是須要重用已經再也不界面顯示的已建立過的Cell。 // // UITableView已經爲咱們實現了這種機制。在UITableView內部有一個緩存池,初始化時使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一個可重用標識,就能夠將這個cell放到緩存池。而後在使用時使用指定的標識去緩存池中取得對應的cell而後修改cell內容便可。 // */ // //因爲此方法調用十分頻繁,cell的 標示 聲明成 靜態變量 有助於性能優化 // static NSString *cellIdentifier = @"UITanleViewCellIdentifierKey1"; // //首先根據標識去緩存池取 // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; // //若是緩存池沒有則從新建立,並放到緩存池中 // if (!cell) { // cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; // } /** * UITableViewCell右側能夠顯示不一樣的圖標,在iOS中稱之爲訪問器,點擊能夠觸發不一樣的事件,例如通信錄右邊的 聯繫人詳情按鈕 ,或者 聲音,Wifi等設置 右邊的開關!!!!!!!!!!!!!!! 在這裏示例將通信錄第一行右邊設置爲 開關 , 其他的右邊設置爲 聯繫人詳情按鈕 */ //因爲此方法調用十分頻繁,cell的 標示 聲明成 靜態變量 有助於性能優化 //注意: 因爲此時咱們須要兩種UITableViewCell樣式,考慮到性能咱們須要在緩存池緩存兩種Cell。 static NSString *cellIdentifier = @"UITableViewCellIdentifierKey1"; static NSString *cellIdentifierForFiestRow = @"UITableViewCellIdentifierKeyWithSwitch"; //首先根據標識去緩存池取 UITableViewCell *cell; if (indexPath.row == 0) { cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierForFiestRow]; }else{ cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; } //若是緩存池沒有則從新建立,並放到緩存池中 if (!cell) { if (indexPath.row == 0) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierForFiestRow]; //在第一行右邊建立開關 UISwitch *sw = [[UISwitch alloc]init]; [sw addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged]; //UISwitch繼承於UIControl而不是UIView(固然UIControl最終也是繼承於UIView),繼承於UIControl的控件使用addTarget添加對應事件而不是代理,同時有「是否可用」、「是否高亮」、「是否選中」等屬性; cell.accessoryView = sw; }else{ cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; cell.accessoryType = UITableViewCellAccessoryDetailButton; } } if (indexPath.row == 0) { ((UISwitch *)cell.accessoryView).tag = indexPath.section; } //cell上的內容(聯繫人 和 電話號碼) cell.textLabel.text = [contact getName]; cell.detailTextLabel.text = contact.phoneNumber; return cell; } #pragma mark 返回每組 頭標題 名稱 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ NSLog(@"生成組(組%li)名稱",(long)section); KCContactGroup *group = contacts[section]; return group.name; } #pragma mark 返回每組 尾部 說明 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ NSLog(@"生成尾部(組%li)詳情",(long)section); KCContactGroup *group = contacts[section]; return group.detail; } #pragma mark 返回每組標題 索引 /** * 你們在使用iPhone通信錄時會發現右側能夠按字母檢索,使用起來很方便,其實這個功能使用UITableView實現很簡單,只要實現數據源協議的一個方法,構建一個分組標題的數組便可實現。數組元素的內容和組標題內容未必徹底一致,UITableView是按照數組元素的索引和每組數據索引順序來定位的而不是按內容查找。 */ - (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView { NSLog(@"生成組索引"); NSMutableArray *indexs = [[NSMutableArray alloc]init]; for (KCContactGroup *group in contacts) { [indexs addObject:group.name]; } return indexs; } #pragma mark - 代理方法 #pragma mark 設置每行高度(每行高度能夠不同) - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 45; } #pragma mark 設置分組標題內容高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ if (section == 0) { return 50; } return 40; } #pragma mark 設置尾部說明內容高度 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 40; } #pragma mark 監聽事件(點擊會跳轉,改值等) //在iOS中點擊某聯繫我的就能夠呼叫這個聯繫人,這時就須要監聽點擊操做,這裏就不演示呼叫聯繫人操做了,咱們演示一下修改人員信息的操做。 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ selectedIndexPath = indexPath; KCContactGroup *group = contacts[indexPath.section]; KCContact *contact = group.contacts[indexPath.row]; NSLog(@"當前選中的組和行%@", selectedIndexPath); //建立彈出窗口 UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示" message:[contact getName] delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"Ok", nil]; alert.alertViewStyle = UIAlertViewStylePlainTextInput;//設置窗口內容樣式 UITextField *textField = [alert textFieldAtIndex:0];//取得文本框 textField.text = contact.phoneNumber;//設置文本框內容 [alert show];//展現窗口 } #pragma mark 彈出窗口的代理方法,用戶保存數據 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ //當點擊了第二個按鈕(Ok) if (buttonIndex == 1) { UITextField *textField = [alertView textFieldAtIndex:0]; //修改模型數據 KCContactGroup *group = contacts[selectedIndexPath.section]; KCContact *contact = group.contacts[selectedIndexPath.row]; contact.phoneNumber = textField.text; // //刷新數據(---------------------------所有刷新--------------------) // [myTableView reloadData]; /** * 在上面的代碼中咱們經過修改模型來改變UI顯示,這種方式是經典的MVC應用,在後面的代碼中會常常看到。固然UI的刷新使用了UITableView的reloadData方法,該方法會從新調用數據源方法,包括計算分組、計算每一個分組的行數,生成單元格等刷新整個UITableView。固然這種方式在實際開發中是不可取的,咱們不可能由於修改了一我的的信息就刷新整個UITableViewView,此時咱們須要採用局部刷新。局部刷新使用起來很簡單,只須要調用UITableView的另一個方法 */ //刷新表格(----------------------局部刷新-------------------------) NSArray *indexPaths=@[selectedIndexPath];//須要局部刷新的單元格的組、行 [myTableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];//後面的參數表明更新時的動畫 } } #pragma mark 重寫狀態樣式方法 -(UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; } #pragma mark 切換開關轉化事件 -(void)switchValueChange:(UISwitch *)sw{ //打印點擊的組 和 開關狀態 NSLog(@"section:%li, switch:%i",(long)sw.tag,sw.on); } #pragma mark 刪除按鈕的方法 -(void)remove:(id)sender{ /** 在UITableView中不管是刪除操做仍是添加操做都是經過修改UITableView的編輯狀態來改變的(除非你不用UITableView自帶的刪除功能)。在刪除按鈕中咱們設置UITableView的編輯狀態: */ //直接經過下面的方法設置編輯狀態沒有動畫 //myTableView.editing=!myTableView.isEditing; //只要一句代碼 //若是判斷爲假 isInsert=false; [myTableView setEditing:!myTableView.isEditing animated:true]; } #pragma mark 添加按鈕的方法 -(void)add:(id)sender{ //只要一句代碼 //若是判斷爲真 isInsert=true; [myTableView setEditing:!myTableView.isEditing animated:true]; } /** * 添加和刪除操做都是設置UITableView的編輯狀態,具體是添加仍是刪除須要根據代理方法-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;的返回值來肯定。所以這裏咱們定義一個變量來記錄點擊了哪一個按鈕,根據點擊按鈕的不一樣在這個方法中返回不一樣的值。 */ #pragma mark 取得當前操做狀態,根據不一樣的狀態左側出現不一樣的操做按鈕 - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{ if (isInsert) { return UITableViewCellEditingStyleInsert; } return UITableViewCellEditingStyleDelete; } #pragma mark 編輯操做(刪除和添加) /** * 用過iOS的朋友都知道,通常這種Cell若是向左滑動右側就會出現刪除按鈕直接刪除就能夠了。其實實現這個功能只要實現代理-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;方法,只要實現了此方法向左滑動就會顯示刪除按鈕。只要點擊刪除按鈕這個方法就會調用,可是須要注意的是不管是刪除仍是添加都是執行這個方法,只是第二個參數類型不一樣。下面看一下具體的刪除實現: */ //實現了此方法向左滑動就會顯示刪除(或添加)圖標 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ KCContactGroup *group = contacts[indexPath.section]; KCContact *contact = group.contacts[indexPath.row]; /** * MVC的思想,要修改UI先修改數據。並且咱們看到了另外一個刷新表格的方法- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;,使用這個方法能夠再刪除以後刷新對應的單元格。 */ if (editingStyle == UITableViewCellEditingStyleDelete) { [group.contacts removeObject:contact]; //考慮到性能這裏不建議使用reloadData // [myTableView reloadData]; //使用下面的方法,既能夠局部刷新又有動畫效果 [myTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom]; //若是當前組中沒有數據,則移除刷新整個表格 if (group.contacts.count == 0) { [contacts removeObject:group]; [myTableView reloadData]; } }else if (editingStyle == UITableViewCellEditingStyleInsert){ KCContact *newContact = [[KCContact alloc]init]; newContact.firstName = @"xiao"; newContact.lastName = @"ming"; newContact.phoneNumber = @"888888888888"; [group.contacts insertObject:newContact atIndex:indexPath.row]; [myTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];//注意這裏沒有使用reloadData刷新 } } #pragma mark 排序 //只要實現這個方法,在編輯狀態右側就有排序圖標 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{ KCContactGroup *sourceGroup = contacts[sourceIndexPath.section]; KCContact *sourceContact = sourceGroup.contacts[sourceIndexPath.row]; KCContactGroup *destinationGroup = contacts[destinationIndexPath.section]; [sourceGroup.contacts removeObject:sourceContact]; if (sourceGroup.contacts.count == 0) { [contacts removeObject:sourceGroup]; [myTableView reloadData]; } [destinationGroup.contacts insertObject:sourceContact atIndex:destinationIndexPath.row]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
須要注意的是上面幾個重點方法的執行順序,請看下圖:
不少時候一個UIViewController中只有一個UITableView,所以蘋果官方爲了方便你們開發直接提供了一個UITableViewController,這個控制器 UITableViewController實現了UITableView數據源和代理協議,內部定義了一個tableView屬性供外部訪問,同時自動鋪滿整個屏幕、自動伸縮以方便咱們的開發。固然UITableViewController也並非簡單的幫咱們定義完UITableView而且設置了數據源、代理而已,它還有其餘強大的功能,例如刷新控件、滾動過程當中固定分組標題等。
有時候一個表格中的數據特別多,檢索起來就顯得麻煩,這個時候能夠實現一個搜索功能幫助用戶查找數據,其實搜索的原理很簡單:修改模型、刷新表格。下面使用UITableViewController簡單演示一下這個功能:
KCContactTableViewController.h
#import <UIKit/UIKit.h> @interface KCContactTableViewController : UITableViewController @end
KCContactTableViewController.m
#import "KCContactTableViewController.h" #import "KCContact.h" #import "KCContactGroup.h" #define kSearchbarHeight 44 @interface KCContactTableViewController ()<UISearchBarDelegate>{ UITableView *tableView; UISearchBar *mysearchBar; NSMutableArray *contacts;//聯繫人模型 NSMutableArray *searchContacts;//符合條件的搜索聯繫人 BOOL isSearching; } @end @implementation KCContactTableViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化數據 [self initData]; //添加搜索框 [self addSearchBar]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source #pragma mark 數據源方法 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { if (isSearching) { return 1; } return contacts.count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (isSearching) { return searchContacts.count; } KCContactGroup *group1 = contacts[section]; return group1.contacts.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ KCContact *contact = nil; if (isSearching) { contact = searchContacts[indexPath.row]; }else{ KCContactGroup *group = contacts[indexPath.section]; contact = group.contacts[indexPath.row]; } static NSString *cellIdentifier = @"UITableViewCellIdentifierKey1"; //首先根據標識去緩存池取 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; //若是緩存池沒有取到,則從新建立並放到緩存池中 if (!cell) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier]; } cell.textLabel.text = [contact getName]; cell.detailTextLabel.text = contact.phoneNumber; return cell; } #pragma mark - 代理方法 #pragma mark 設置分組標題 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ KCContactGroup *group = contacts[section]; return group.name; } #pragma mark - 搜索框代理 #pragma mark 取消搜索 - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{ isSearching = NO; mysearchBar.text = @""; [self.tableView reloadData]; } #pragma mark 輸入搜索關鍵字 - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{ if ([mysearchBar.text isEqual:@""]) { isSearching = NO; [self.tableView reloadData]; return; } [self searchDataWithKeyWord:mysearchBar.text]; } #pragma mark 點擊虛擬鍵盤上的搜索時 - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{ [self searchDataWithKeyWord:searchBar.text]; [mysearchBar resignFirstResponder];//放棄第一響應者對象,關閉虛擬鍵盤 } #pragma mark 重寫狀態樣式方法 - (UIStatusBarStyle)preferredStatusBarStyle{ return UIStatusBarStyleLightContent; } #pragma mark 加載數據 - (void)initData{ contacts = [[NSMutableArray alloc]init]; KCContact *contact1 = [KCContact initWithFirstName:@"liu" andLastName:@"bo" andPhoneNumber:@"18811111111"]; KCContact *contact2 = [KCContact initWithFirstName:@"wang" andLastName:@"zhaohua" andPhoneNumber:@"18855555555"]; KCContactGroup *group1 = [KCContactGroup initWithName:@"jiaren" andDetail:@"womenshiyijiaren" andContacts:[NSMutableArray arrayWithObjects:contact1, contact2, nil]]; [contacts addObject:group1]; KCContact *contact3 = [KCContact initWithFirstName:@"zhang" andLastName:@"bing" andPhoneNumber:@"12345678900"]; KCContact *contact4 = [KCContact initWithFirstName:@"wu" andLastName:@"wei" andPhoneNumber:@"98765432100"]; KCContact *contact5 = [KCContact initWithFirstName:@"zhang" andLastName:@"san" andPhoneNumber:@"12345612345"]; KCContactGroup *group2 = [KCContactGroup initWithName:@"pengyou" andDetail:@"womenshipengyou" andContacts:[NSMutableArray arrayWithObjects:contact3, contact4, contact5, nil]]; [contacts addObject:group2]; KCContact *contact6 = [KCContact initWithFirstName:@"li" andLastName:@"si" andPhoneNumber:@"12345555555"]; KCContact *contact7 = [KCContact initWithFirstName:@"wang" andLastName:@"wu" andPhoneNumber:@"88888888888"]; KCContactGroup *group3 = [KCContactGroup initWithName:@"tongxue" andDetail:@"womenshitongxue" andContacts:[NSMutableArray arrayWithObjects:contact6, contact7, nil]]; [contacts addObject:group3]; KCContact *contact8 = [KCContact initWithFirstName:@"hi" andLastName:@"pi" andPhoneNumber:@"12345555555"]; KCContact *contact9 = [KCContact initWithFirstName:@"kang" andLastName:@"gu" andPhoneNumber:@"88888888888"]; KCContact *contact10 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact11 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact12 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group4 = [KCContactGroup initWithName:@"qinqi" andDetail:@"womenshiqinqi" andContacts:[NSMutableArray arrayWithObjects:contact8, contact9, contact10, contact11, contact12, nil]]; [contacts addObject:group4]; KCContact *contact13 = [KCContact initWithFirstName:@"roi" andLastName:@"sfi" andPhoneNumber:@"12345555555"]; KCContact *contact14 = [KCContact initWithFirstName:@"fang" andLastName:@"ii" andPhoneNumber:@"88888888888"]; KCContact *contact15 = [KCContact initWithFirstName:@"tyng" andLastName:@"rd" andPhoneNumber:@"88888888888"]; KCContactGroup *group5 = [KCContactGroup initWithName:@"tongshi" andDetail:@"womenshitongshi" andContacts:[NSMutableArray arrayWithObjects:contact13, contact14, contact15, nil]]; [contacts addObject:group5]; } #pragma mark 搜索造成新數據 - (void)searchDataWithKeyWord:(NSString *)keyWord{ isSearching = YES; searchContacts = [NSMutableArray array]; [contacts enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { KCContactGroup *group = obj; [group.contacts enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { KCContact *contact = obj; if ([contact.firstName.uppercaseString containsString:keyWord.uppercaseString] || [contact.lastName.uppercaseString containsString:keyWord.uppercaseString] || [contact.phoneNumber containsString:keyWord]) { [searchContacts addObject:contact]; } }]; }]; //刷新表格 [self.tableView reloadData]; } #pragma mark 添加搜索框 - (void)addSearchBar{ CGRect searchBarRect = CGRectMake(0, 0, self.view.frame.size.width, 44); mysearchBar = [[UISearchBar alloc]initWithFrame:searchBarRect]; mysearchBar.placeholder = @"請輸入姓名";//淺色提示文字 mysearchBar.keyboardType = UIKeyboardTypeAlphabet;//鍵盤類型 mysearchBar.autocorrectionType = UITextAutocorrectionTypeNo;//自動糾錯類型 mysearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;//哪一次shitf被自動按下 mysearchBar.showsCancelButton = YES;//顯示取消按鈕 //添加搜索框到頁眉位置 mysearchBar.delegate = self; self.tableView.tableHeaderView = mysearchBar; } /* - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath]; // Configure the cell... return cell; } */ /* // Override to support conditional editing of the table view. - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the specified item to be editable. return YES; } */ /* // Override to support editing the table view. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the row from the data source [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } } */ /* // Override to support rearranging the table view. - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { } */ /* // Override to support conditional rearranging of the table view. - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the item to be re-orderable. return YES; } */ /* #pragma mark - Table view delegate // In a xib-based application, navigation from a table can be handled in -tableView:didSelectRowAtIndexPath: - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here, for example: // Create the next view controller. <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:<#@"Nib name"#> bundle:nil]; // Pass the selected object to the new view controller. // Push the view controller. [self.navigationController pushViewController:detailViewController animated:YES]; } */ /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
大神連接 - 很重要:
http://www.cnblogs.com/kenshincui/p/3931948.html#introduction
if ([tableView isEqual:leftTableView]) { static NSString *cellId = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId]; if (cell == nil) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId]; } cell.textLabel.text = @"陝西"; //選中cell後爲紫色,對新生成的cell添加一個背景view:(將cell在選擇時背景置爲紫色) UIView *aVIew = [[UIView alloc]initWithFrame:cell.frame]; aVIew.backgroundColor = [UIColor purpleColor]; cell.selectedBackgroundView = aVIew; return cell; }