文章来源:http://blog.csdn.net/cocoarannie/article/details/11183067
上篇博客写了关于性能优化以及手工绘制自定义单元格内容,这篇我们利用TableView的Section的Header来实现类似QQ好友列表的效果。
TableView有一个代理方法
这个方法返回一个UIView对象,我们可以将一个Button对象设为这个Section的Header,在点击它的时候展开列表内容。
简单地看下假的好友列表数据
一个array中包含多个dictionary,字典中又包括组别的名字以及好友列表,好友也用一个字典来表示,分别有名称,是否在线以及头像图片名字。
加载数据
- - (void)loadData
- {
- NSString *path = [[NSBundle mainBundle] pathForResource:@"friends" ofType:@"plist"];
- _dataList = [NSArray arrayWithContentsOfFile:path];
- _headers = [NSMutableDictionary dictionaryWithCapacity:_dataList.count];
- _groupNames = [NSMutableArray arrayWithCapacity:_dataList.count];
- for (NSInteger i = 0; i < _dataList.count; i++)
- {
- NSDictionary *dict = _dataList[i];
- [_groupNames addObject:dict[@"groupname"]];
- }
- }
之后我们开始写一个自定义的头部按钮来方便我们想要的布局
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- UIImage *image = [UIImage imageNamed:@"arrow-right"];
- [self setImage:image forState:UIControlStateNormal];
- self.imageView.contentMode = UIViewContentModeScaleAspectFit;
- //[self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
- _open = NO;
- }
- return self;
- }
- - (void)setOpen:(BOOL)open
- {
- _open = open;
- //设定点击旋转动画效果
- [UIView beginAnimations:nil context:nil];
- self.imageView.transform = CGAffineTransformMakeRotation(self.isOpen?M_PI_2:0);
- [UIView commitAnimations];
- }
有一个BOOL型的成员_open来记录button是否被点击的状态,在点击时,左侧的图片有一个短暂的旋转动画效果。
然后设置图片以及标题的位置
- //图像显示位置
- - (CGRect)imageRectForContentRect:(CGRect)contentRect
- {
- return CGRectMake(RMarginX, RMarginY, RIconSide, RIconSide);
- }
- //标题显示位置
- - (CGRect)titleRectForContentRect:(CGRect)contentRect
- {
- return CGRectMake(RIconSide + 4*RMarginX, 0, contentRect.size.width, contentRect.size.height);
- }
在drawRect中还绘制了底部的分割线以及光泽,不过由于背景没有绘制渐变,光泽效果有些突兀,若想具体了解绘制方法的使用,可以参见UIKit和Core Graphics绘图——绘制光泽,仿射变换与矩阵变换
绘制底边
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextSaveGState(context);
- CGContextSetStrokeColorWithColor(context, [UIColor darkGrayColor].CGColor);
- CGContextMoveToPoint(context, 0, rect.size.height);
- CGContextAddLineToPoint(context, 320, rect.size.height);
- CGContextSetLineWidth(context, 2.0f);
- CGContextStrokePath(context);
- CGContextRestoreGState(context);
然后是光泽效果
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- UIColor *light = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.1];
- UIColor *dark = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.35];
- NSArray *colors = @[(__bridge id)light.CGColor, (__bridge id)dark.CGColor];
- CGFloat locations[] = {0.0, 1.0};
- CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
- CGContextSaveGState(context);
- CGPoint start = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
- CGPoint end = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
- CGContextDrawLinearGradient(context, gradient, start, end, 0);
- CGColorSpaceRelease(colorSpace);
- CGGradientRelease(gradient);
- CGContextRestoreGState(context);
接着我们还需要自定义一个单元格类来接受和绘制数据,
具体实现类似于上篇博客中介绍的手工绘制单元格的内容
这里只看数据绑定的部分
- - (void)bindFriend:(NSDictionary *)myFriend
- {
- _name = myFriend[@"name"];
- _online = [myFriend[@"isonline"] boolValue];
- _headerImage = [UIImage imageNamed:myFriend[@"imagename"]];
- [self setNeedsDisplay];
- }
在完成头部绘制以及单元格绘制的准备后,我们就可以在控制器中实现代理方法,讲数据排版到界面上了。
显示头部视图
- - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
- {
- HeaderButton *header = _headers[@(section)];
- if (!header)
- {
- header = [HeaderButton buttonWithType:UIButtonTypeCustom];
- header.bounds = CGRectMake(0, 0, 320, RHeaderHeight);
- header.backgroundColor = [UIColor colorWithRed:0.4 green:0.4 blue:0.8 alpha:1.0];
- header.titleLabel.font = [UIFont systemFontOfSize:16.0f];
- NSString *title = _groupNames[section];
- [header setTitle:title forState:UIControlStateNormal];
- [header addTarget:self action:@selector(expandFriends:) forControlEvents:UIControlEventTouchUpInside];
- [_headers setObject:header forKey:@(section)];
- }
- return header;
- }
头部点击的监听方法
- - (void)expandFriends:(HeaderButton *)header
- {
- header.open = !header.isOpen;
- [self.tableView reloadData];
- }
点击的时候改变header的_open值,然后刷新视图内容。
根据header的_open来确定是否显示section中的列表
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- HeaderButton *header = _headers[@(section)];
- NSArray *array = [self arrayWithSection:section];
- NSInteger count = header.isOpen?array.count:0;
- return count;
- }
绑定数据并且显示单元格
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- HRFriendsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- NSArray *array = [self arrayWithSection:indexPath.section];
- [cell bindFriend:array[indexPath.row]];
- return cell;
- }
这样我们的工作几乎就完成了,下面来看一下效果图
具体的demo源码:点击打开链接
以上就是本篇博客全部内容,欢迎指正和交流。转载请注明出处~