对于UITableView,相信大家都并不陌生,每一个iOS app 几乎都离不开UITableViewCell,创建UITableViewCell的过程也很简单,所以也无需纪录,昨天在工作闲余时间学习了一下UITableView更细致的一些功能,这些功能使得UITableView更加强大和使用。
1、删除
删除通常有两种方式:
一是点击一个按钮后,所有的tableViewCell的最左边都出现一个红色的按钮,中间有一条横杆,点击这个按钮后右侧就会出现删除按钮
二是滑动tableViewCell,右侧会出现删除按钮。
先说第一种的实现:
创建一个UIViewController类,通过Interface Builder添加一个UItableView,为这个类添加一个数组作为成员变量,用于记录tableView的数据,头文件代码如下:
#import <UIKit/UIKit.h> @interface ViewControllerX : UIViewController<UITableViewDataSource,UITableViewDelegate> @property (nonatomic,retain) IBOutlet UITableView *SeanTableView; @property (nonatomic,retain) NSMutableArray *array; @end
在类的实现文件的ViewDidRoad方法中,加载数组数据,创建两个UIBarButtonItem类对象,即创建一个垃圾桶样式的按钮和一个➕样式的按钮,代码如下:
- (void)viewDidLoad { [super viewDidLoad]; self.array = [NSMutableArray arrayWithArray:@[@"Lin Sean",@"Lin wade",@"D wade",@"Lin James",@"CB"]]; UIBarButtonItem *left = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(delete)]; self.navigationItem.leftBarButtonItem = left; UIBarButtonItem *right = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)]; self.navigationItem.rightBarButtonItem = right; }
要实现第一种删除方法,实际上是要让tableView进入编辑模式,所以垃圾筒按钮的响应函数代码如下:
- (void) delete { [self.SeanTableView setEditing:YES animated:YES]; //使tableView进入编辑模式 }
到这里,点击垃圾筒按钮,就可以出现以下的情况了
但是,这里点击了delete按钮,也没有反应,因为还需要实现协议的一个方法
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
接着说滑动删除的方法:
这里一下子跳到滑动删除的原因,是因为只要实现了上述提到的
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath方法,tableView就能实现滑动删除了。实现这个方法的代码如下:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { [self.array removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; }
方法里首先肯定是要对数组进行删除操作,然后就是对tableView进行操作,这里没有在删除数组之后执行tableView reloadData的原因是reloadData这个方法是重新刷新整个tableView,比较耗费性能,而这里知识更改了一行数据,所以只要调用上面的第二个语句的方法,系统就会重新刷新一行的数据,这样效率会高很多。
至此,删除功能就能够完成了,可能这里还会存在很多错漏之处,但这也只是简介,更精密的代码还有待大家更具实际需求来做具体的设计。
2、添加
添加其实跟删除很类似,点击了一个添加按钮之后,所有的tableViewCell前面都会弹出一个绿色的按钮。
操作方法也是一样,当点击了➕按钮后,tableView进入编辑模式,代码如下:
- (void) add { [self.SeanTableView setEditing:YES animated:YES]; }
这里就有问题了,点击删除也是进入编辑模式,点击添加也是进入编辑模式,那系统是怎样区分是删除还是添加呢?
这里就需要再实现另一个协议的方法
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath,为了区别到底是点了那个按钮,我们还需要在头文件创建一个标志变量来记录当前是那种模式。下面代码中的isInsert就是标志变量。
- (void) delete { isInsert = NO; // 加上标志记录 [self.SeanTableView setEditing:YES animated:YES]; } - (void) add { isInsert = YES; // 加上标志纪录 [self.SeanTableView setEditing:YES animated:YES]; }
// 使tableView进入何种编辑模式,由这个函数的返回值进行决定 - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { if (isInsert == YES) { return UITableViewCellEditingStyleInsert; } else { return UITableViewCellEditingStyleDelete; } }
到这里,就可以点击垃圾桶进入删除的编辑模式,点击➕按钮就进入添加的编辑模式了。但是,这时即便进入了添加模式,点击左侧的添加按钮,会发现响应的依然是删除的功能。这事因为进入编辑模式后,系统执行何种操作,还是由上述的
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
方法决定的,这个方法的参数editingStyle就是用户判断是何种编辑模式的,所以还需要在该方法中进行判断,代码如下:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [self.array removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewAutomaticDimension]; } else { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; [self.array insertObject:cell.textLabel.text atIndex:indexPath.row]; [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewAutomaticDimension]; } }
这样,一个可以大概实现增加和删除的UITableView就粗略地实现了,效果如下:
3.排序
其实排序,也无非是实现协议中的方法就可以实现了,只不过你以后tableViewCell后,你的数组应该如何调整,这就是逻辑问题了,需要自己去实现。
要使得tableView可以在进入编辑模式后可以排序,只要实现一下这个方法就行了,实现代码可以为空。如下:
- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { //这里为空,进入编辑模式后,tableView的cell也可以拖动排序,但是一般需要在这个函数里面进行一个数组元素位置的调整 }
效果如下:
这时只要长按右侧的三道杠,然后拖动cell,就可以排序了。
4、搜索过滤
搜索过滤与前面三个不同,它不属于tableView的编辑模式下进行的操作。但是在学习的过程中也接触到了,而且非常常用,所以也纪录一下
首先肯定是要添加一个搜索栏,这里为了简便,我把它添加到了navigationbar的titleView里面去,为完善搜索栏的各种功能,还需在头文件中实现UISearchBarDelegate协议,代码如下:
@interface ViewControllerX : UIViewController<UITableViewDataSource,UITableViewDelegate,UISearchBarDelegate>
<pre name="code" class="objc">- (void)viewDidLoad { [super viewDidLoad]; self.array = [NSMutableArray arrayWithArray:@[@"Lin Sean",@"Lin wade",@"D wade",@"Lin James",@"CB"]]; UIBarButtonItem *left = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(delete)]; self.navigationItem.leftBarButtonItem = left; UIBarButtonItem *right = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)]; self.navigationItem.rightBarButtonItem = right; isInsert = NO; // 在navigationBar添加一个搜索栏 UISearchBar *sb = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 60, 20)]; sb.showsCancelButton = YES; self.navigationItem.titleView = sb; sb.delegate = self; self.searchArray = [[NSMutableArray alloc]init]; } // 点击搜索栏cancel按钮时执行的操作 - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; //键盘退回 [self.SeanTableView reloadData]; }
要实时监测searchbar输入的内容,根据内容进行表格数据的过滤,我们需要实现以下的协议方法,并创建一个新的数组和一个标志变量,用户纪录搜索的结果和判断当前是否正在搜索,代码如下:
头文件:
@interface ViewControllerX : UIViewController<UITableViewDataSource,UITableViewDelegate,UISearchBarDelegate> { bool isInsert; bool isSearch; } @property (nonatomic,retain) IBOutlet UITableView *SeanTableView; @property (nonatomic,retain) NSMutableArray *array; @property (nonatomic,retain) NSMutableArray *searchArray; @end
实现文件:
// 点击搜索栏cancel按钮时执行的操作 - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { isSearch = NO; [searchBar resignFirstResponder]; //键盘退回 [self.SeanTableView reloadData]; } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { isSearch = YES; if (self.searchArray.count != 0) { [self.searchArray removeAllObjects]; } for (id sean in self.array) { if ([sean containsString:searchText]) { [self.searchArray addObject:sean]; [self.SeanTableView reloadData]; } else { [self.SeanTableView reloadData]; } } }
因为在搜索栏输入内容的时候需要tableView需要reloadData,所以需要修改代码如下:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (isSearch == YES) { return self.searchArray.count; } return self.array.count; } - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *str = nil; if (isSearch == YES) { str = [self.searchArray objectAtIndex:indexPath.row]; } else { str = [self.array objectAtIndex:indexPath.row]; } UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (cell == nil) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; } cell.textLabel.text = str; return cell; }
至此,一个简单的搜索功能就实现了。效果如下:
头文件的完整代码如下:
#import <UIKit/UIKit.h> @interface ViewControllerX : UIViewController<UITableViewDataSource,UITableViewDelegate,UISearchBarDelegate> { bool isInsert; bool isSearch; } @property (nonatomic,retain) IBOutlet UITableView *SeanTableView; @property (nonatomic,retain) NSMutableArray *array; @property (nonatomic,retain) NSMutableArray *searchArray; @end
实现文件的完整代码如下:
#import "ViewControllerX.h" @interface ViewControllerX () @end @implementation ViewControllerX - (void)viewDidLoad { [super viewDidLoad]; self.array = [NSMutableArray arrayWithArray:@[@"Lin Sean",@"Lin wade",@"D wade",@"Lin James",@"CB"]]; UIBarButtonItem *left = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(delete)]; self.navigationItem.leftBarButtonItem = left; UIBarButtonItem *right = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add)]; self.navigationItem.rightBarButtonItem = right; isInsert = NO; // 在navigationBar添加一个搜索栏 UISearchBar *sb = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 60, 20)]; sb.showsCancelButton = YES; self.navigationItem.titleView = sb; sb.delegate = self; self.searchArray = [[NSMutableArray alloc]init]; } // 点击搜索栏cancel按钮时执行的操作 - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { isSearch = NO; [searchBar resignFirstResponder]; //键盘退回 [self.SeanTableView reloadData]; } - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { isSearch = YES; if (self.searchArray.count != 0) { [self.searchArray removeAllObjects]; } for (id sean in self.array) { if ([sean containsString:searchText]) { [self.searchArray addObject:sean]; [self.SeanTableView reloadData]; } else { [self.SeanTableView reloadData]; } } } - (void) delete { isInsert = NO; // 加上标志记录 [self.SeanTableView setEditing:YES animated:YES]; } - (void) add { isInsert = YES; // 加上标志纪录 [self.SeanTableView setEditing:YES animated:YES]; } - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { if (isInsert == YES) { return UITableViewCellEditingStyleInsert; } else { return UITableViewCellEditingStyleDelete; } } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [self.array removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewAutomaticDimension]; } else { UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; [self.array insertObject:cell.textLabel.text atIndex:indexPath.row]; [tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewAutomaticDimension]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (isSearch == YES) { return self.searchArray.count; } return self.array.count; } - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *str = nil; if (isSearch == YES) { str = [self.searchArray objectAtIndex:indexPath.row]; } else { str = [self.array objectAtIndex:indexPath.row]; } UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (cell == nil) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; } cell.textLabel.text = str; return cell; } - (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { } @end