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


上篇博客写了关于性能优化以及手工绘制自定义单元格内容,这篇我们利用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源码:点击打开链接


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



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个简单的 iOS UITableView 的代码实现示例: 1. 首先,在你的视图控制器中添加 UITableView 属性: ``` @interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> @property (nonatomic, strong) UITableView *tableView; @end ``` 2. 在 viewDidLoad 方法中初始化 UITableView: ``` - (void)viewDidLoad { [super viewDidLoad]; // 初始化 UITableView self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; self.tableView.delegate = self; self.tableView.dataSource = self; [self.view addSubview:self.tableView]; } ``` 3. 实现 UITableViewDataSource 协议中的方法: ``` // 返回 UITableView 中的 section 数量 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } // 返回 UITableView 中某个 section 中的 row 数量 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 10; } // 返回 UITableView 中某个 indexPath 的 cell - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"MyCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; } cell.textLabel.text = [NSString stringWithFormat:@"Cell %ld", (long)indexPath.row]; return cell; } ``` 4. 实现 UITableViewDelegate 协议中的方法,比如设置 cell 的高度: ``` - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 44.0f; } ``` 以上就是一个简单的 UITableView 的代码实现示例。需要注意的是,UITableView 必须指定 delegate 和 dataSource,而且需要实现 UITableViewDataSource 和 UITableViewDelegate 协议中的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值