现在的位置: 首页 > 综合 > 正文

IOS详解TableView —— QQ好友列表的实现

2014年09月05日 ⁄ 综合 ⁄ 共 5312字 ⁄ 字号 评论关闭

文章来源:http://blog.csdn.net/cocoarannie/article/details/11183067

上篇博客写了关于性能优化以及手工绘制自定义单元格内容,这篇我们利用TableView的Section的Header来实现类似QQ好友列表的效果。

TableView有一个代理方法

这个方法返回一个UIView对象,我们可以将一个Button对象设为这个Section的Header,在点击它的时候展开列表内容。

简单地看下假的好友列表数据

一个array中包含多个dictionary,字典中又包括组别的名字以及好友列表,好友也用一个字典来表示,分别有名称,是否在线以及头像图片名字。

加载数据

  1. - (void)loadData  
  2. {  
  3.     NSString *path = [[NSBundle mainBundle] pathForResource:@"friends" ofType:@"plist"];  
  4.     _dataList = [NSArray arrayWithContentsOfFile:path];  
  5.     _headers = [NSMutableDictionary dictionaryWithCapacity:_dataList.count];  
  6.       
  7.     _groupNames = [NSMutableArray arrayWithCapacity:_dataList.count];  
  8.     for (NSInteger i = 0; i < _dataList.count; i++)  
  9.     {  
  10.         NSDictionary *dict = _dataList[i];  
  11.         [_groupNames addObject:dict[@"groupname"]];  
  12.     }  
  13. }  



之后我们开始写一个自定义的头部按钮来方便我们想要的布局

  1. - (id)initWithFrame:(CGRect)frame  
  2. {  
  3.     self = [super initWithFrame:frame];  
  4.     if (self) {  
  5.         UIImage *image = [UIImage imageNamed:@"arrow-right"];  
  6.         [self setImage:image forState:UIControlStateNormal];  
  7.         self.imageView.contentMode = UIViewContentModeScaleAspectFit;  
  8.         //[self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  
  9.         _open = NO;  
  10.     }  
  11.     return self;  
  12. }  
  13.   
  14. - (void)setOpen:(BOOL)open  
  15. {  
  16.     _open = open;  
  17.     //设定点击旋转动画效果  
  18.     [UIView beginAnimations:nil context:nil];  
  19.     self.imageView.transform = CGAffineTransformMakeRotation(self.isOpen?M_PI_2:0);  
  20.     [UIView commitAnimations];  
  21. }  



有一个BOOL型的成员_open来记录button是否被点击的状态,在点击时,左侧的图片有一个短暂的旋转动画效果。

然后设置图片以及标题的位置

  1. //图像显示位置  
  2. - (CGRect)imageRectForContentRect:(CGRect)contentRect  
  3. {  
  4.     return CGRectMake(RMarginX, RMarginY, RIconSide, RIconSide);  
  5. }  
  6.   
  7. //标题显示位置  
  8. - (CGRect)titleRectForContentRect:(CGRect)contentRect  
  9. {  
  10.     return CGRectMake(RIconSide + 4*RMarginX, 0, contentRect.size.width, contentRect.size.height);  
  11. }  


在drawRect中还绘制了底部的分割线以及光泽,不过由于背景没有绘制渐变,光泽效果有些突兀,若想具体了解绘制方法的使用,可以参见UIKit和Core
Graphics绘图——绘制光泽,仿射变换与矩阵变换

绘制底边

  1. CGContextRef context = UIGraphicsGetCurrentContext();  
  2.   
  3. CGContextSaveGState(context);  
  4. CGContextSetStrokeColorWithColor(context, [UIColor darkGrayColor].CGColor);  
  5. CGContextMoveToPoint(context, 0, rect.size.height);  
  6. CGContextAddLineToPoint(context, 320, rect.size.height);  
  7. CGContextSetLineWidth(context, 2.0f);  
  8. CGContextStrokePath(context);  
  9. CGContextRestoreGState(context);  


然后是光泽效果

  1. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();  
  2. UIColor *light = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.1];  
  3. UIColor *dark = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.35];  
  4. NSArray *colors = @[(__bridge id)light.CGColor, (__bridge id)dark.CGColor];  
  5. CGFloat locations[] = {0.0, 1.0};  
  6.   
  7. CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);  
  8.   
  9. CGContextSaveGState(context);  
  10. CGPoint start = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));  
  11. CGPoint end = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));  
  12. CGContextDrawLinearGradient(context, gradient, start, end, 0);  
  13.   
  14. CGColorSpaceRelease(colorSpace);  
  15. CGGradientRelease(gradient);  
  16. CGContextRestoreGState(context);  


接着我们还需要自定义一个单元格类来接受和绘制数据,

具体实现类似于上篇博客中介绍的手工绘制单元格的内容

这里只看数据绑定的部分

  1. - (void)bindFriend:(NSDictionary *)myFriend  
  2. {  
  3.     _name = myFriend[@"name"];  
  4.     _online = [myFriend[@"isonline"] boolValue];  
  5.     _headerImage = [UIImage imageNamed:myFriend[@"imagename"]];  
  6.       
  7.     [self setNeedsDisplay];  
  8. }  



在完成头部绘制以及单元格绘制的准备后,我们就可以在控制器中实现代理方法,讲数据排版到界面上了。

显示头部视图

  1. - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section  
  2. {  
  3.     HeaderButton *header = _headers[@(section)];  
  4.     if (!header)  
  5.     {  
  6.         header = [HeaderButton buttonWithType:UIButtonTypeCustom];  
  7.         header.bounds = CGRectMake(0, 0, 320, RHeaderHeight);  
  8.         header.backgroundColor = [UIColor colorWithRed:0.4 green:0.4 blue:0.8 alpha:1.0];  
  9.         header.titleLabel.font = [UIFont systemFontOfSize:16.0f];  
  10.         NSString *title = _groupNames[section];  
  11.         [header setTitle:title forState:UIControlStateNormal];  
  12.         [header addTarget:self action:@selector(expandFriends:) forControlEvents:UIControlEventTouchUpInside];  
  13.         [_headers setObject:header forKey:@(section)];  
  14.     }  
  15.     return header;  
  16. }  


头部点击的监听方法

  1. - (void)expandFriends:(HeaderButton *)header  
  2. {  
  3.     header.open = !header.isOpen;  
  4.     [self.tableView reloadData];  
  5. }  


点击的时候改变header的_open值,然后刷新视图内容。

根据header的_open来确定是否显示section中的列表

  1. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section  
  2. {  
  3.     HeaderButton *header = _headers[@(section)];  
  4.     NSArray *array = [self arrayWithSection:section];  
  5.     NSInteger count = header.isOpen?array.count:0;  
  6.     return count;  
  7. }  



绑定数据并且显示单元格

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  
  2. {  
  3.     HRFriendsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];  
  4.       
  5.     NSArray *array = [self arrayWithSection:indexPath.section];  
  6.     [cell bindFriend:array[indexPath.row]];  
  7.       
  8.     return cell;  
  9. }  



这样我们的工作几乎就完成了,下面来看一下效果图

具体的demo源码:点击打开链接

以上就是本篇博客全部内容,欢迎指正和交流。转载请注明出处~

抱歉!评论已关闭.