在上一篇(IOS学习之tableview示例)基础上,实现常见的“加载更多功能”,即最下方的cell点击可以触发加载更多的数据源,并增加cell显示.
本篇只重点说明新增的地方,和上一篇重复的知识点,不再累述。先上个最终的效果图:
还是直接上代码, 首先头文件里,
- @interfaceViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
- {
- UITableView * m_tableView;
- NSMutableArray*arrayList;
- }
- @property (nonatomic ,retain) UITableView * m_tableView;
- -(void)appendCellWith:(NSMutableArray *)data;
- -(void) doAllTest;
不多说,直接看.m文件
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- {
- //设置头标题
- UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 40)];
- label.text = @"加载更多测试";
- tableView.tableHeaderView = label;
- m_tableView = tableView;//注意这里
- return 1;
- }
这个函数里有个关键就是把tableview的变量实例取出来,因为后面有成员函数要显示的调用。
下面这个不需要多说,
- - (UITableViewCell*)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell =[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil)
- {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- }
- NSLog(@"%d",[arrayList count]);
- if ([indexPath row] <= [arrayList count] - 1)
- {
- cell.textLabel.textColor =[UIColor orangeColor];
- cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
- }
- else
- {
- cell.textLabel.textColor =[UIColor blueColor];
- cell.textLabel.text = @"点击加载更多";
- }
- returncell;
- }
继续上代码:
- -(void)tableView:(UITableView *)tableViewdidSelectRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if (indexPath.row == [arrayList count])
- {
- [self doAllTest];
- NSIndexPath *index = [NSIndexPath indexPathForRow:indexPath.row+3inSection:0];
- NSLog(@"new indexPath.row:%u", index.row);
- [tableView deselectRowAtIndexPath:indexanimated:YES];
- return;
- }
- }
deselectRowAtIndexPath 这个调用是取消选定状态,这一句如果不加,加载完新的cell后,最后一个cell依然是选定的状态.
最后两个方法实现,
- -(void)appendCellWith:(NSMutableArray *)data
- {
- NSLog(@"appendTableWith");
- for (int i = 0 ; i < [data count] ; i++)
- {
- [arrayList addObject:[data objectAtIndex:i]];
- }
- NSMutableArray*insertIndexPaths = [NSMutableArray arrayWithCapacity:10];
- for (int j = 0; j < [data count]; j++)
- {
- NSIndexPath *newPath =[NSIndexPath indexPathForRow:[arrayList indexOfObject:[data objectAtIndex:j]] inSection:0];
- [insertIndexPaths addObject:newPath];
- }
- [m_tableView insertRowsAtIndexPaths:insertIndexPathswithRowAnimation:UITableViewRowAnimationFade];
- }
- -(void) doAllTest
- {
- NSLog(@"doAllTest");
- NSMutableArray *moreArray = nil;
- moreArray = [NSMutableArray arrayWithObjects:@"苹果",@"橘子",@"香蕉", nil nil];
- [self appendCellWith:moreArray];
- }
另外再说一种方法,这种方法是网上看到的,比我的实现复杂一些,用到了多线程,但是从软件设计的角度看,是很好的,因为这种”加载更多”功能,是应该在后台开一个线程去获取新的数据源比较好,然后再用新的数据源更新主线程的UI显示。看代码自会明白.
先增加一个函数声明和实现,
- -(void)loadMore;
- -(void)loadMore
- {
- NSLog(@"loadMore");
- NSMutableArray *moreArray = nil;
- moreArray = [NSMutableArray arrayWithObjects:@"苹果",@"橘子",@"香蕉", nil nil];
- if (moreArray != nil )
- {
- [self performSelectorOnMainThread:@selector(appendCellWith:)withObject:moreArray waitUntilDone:YES];
- }
- }
在主线程之外的线程更新主线程所显示的界面元素,不能直接调用主线程的类的更新界面的方法,否则界面看不到任何结果,要调用一个方法:
performSelectorOnMainThread.
waitUntilDone指定当前线程是否要被阻塞?另外注意一下selector里面这个冒号,加冒号表示这个方法存在参数,没有参数就不用加冒号.
然后就可以直接调用这个子线程了:
- -(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- {
- if (indexPath.row == [arrayList count])
- {
- [self performSelectorInBackground:@selector(loadMore)withObject:nil];
- NSLog(@"indexPath.row:%u",indexPath.row);
- [tableView deselectRowAtIndexPath:indexPathanimated:YES];
- return;
- }
- }
在服务器端获取完数据通过后台使用多线程方式自动更新UI, 通常的方法是
使用NSObject类的方法performSelectorInBackground:withObject:来创建一个线程。调用之后,会立即创建一个线程并执行selector方法
注意到这里取消选择状态时,index并没有加3,是因为这个时候索引还没有变,只是开启了一个子线程去后台处理,要好好体会与上面的差异性。或者可以用同步和异步来理解是否容易一些呢?
源码下载:
http://download.youkuaiyun.com/detail/pony_maggie/7163881