热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

文章来源:http:blog.csdn.netcocoaranniearticledetails11183067上篇博客写了关于性能优化以及手工绘制自定义单元格内容,这篇我们

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

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


TableView有一个代理方法


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


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




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


加载数据


[cpp] view plaincopy
  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. }  


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


[cpp] view plaincopy
  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是否被点击的状态,在点击时,左侧的图片有一个短暂的旋转动画效果。


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


[cpp] view plaincopy
  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绘图——绘制光泽,仿射变换与矩阵变换


绘制底边


[cpp] view plaincopy
  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);  

然后是光泽效果


[cpp] view plaincopy
  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);  

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

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


这里只看数据绑定的部分


[cpp] view plaincopy
  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. }  


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


显示头部视图


[cpp] view plaincopy
  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. }  

头部点击的监听方法


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

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


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

[cpp] view plaincopy
  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. }  


绑定数据并且显示单元格


[cpp] view plaincopy
  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源码:点击打开链接


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



推荐阅读
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 微信公众号推送模板40036问题
    返回码错误码描述说明40001invalidcredential不合法的调用凭证40002invalidgrant_type不合法的grant_type40003invalidop ... [详细]
  • 开发技巧:在Interface Builder中实现UIButton文本居中对齐的方法与步骤
    开发技巧:在Interface Builder中实现UIButton文本居中对齐的方法与步骤 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • 在 `UITableViewController` 中采用简洁的平面样式布局时,可以通过优化代码实现单元格扩展至屏幕边缘的效果,同时确保节标题以分组样式呈现,从而提升用户体验和界面美观度。通过这种方式,可以更好地组织和展示列表内容,使其更加清晰和有序。 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • 微信小程序实现类似微博的无限回复功能,内置云开发数据库支持
    本文详细介绍了如何利用微信小程序实现类似于微博的无限回复功能,并充分利用了微信云开发的数据库支持。文中不仅提供了关键代码片段,还包含了完整的页面代码,方便开发者按需使用。此外,HTML页面中包含了一些示例图片,开发者可以根据个人喜好进行替换。文章还将展示详细的数据库结构设计,帮助读者更好地理解和实现这一功能。 ... [详细]
  • 蓝桥杯物联网基础教程:通过GPIO输入控制LED5的点亮与熄灭
    本教程详细介绍了如何利用STM32的GPIO接口通过输入信号控制LED5的点亮与熄灭。内容涵盖GPIO的基本配置、按键检测及LED驱动方法,适合具有STM32基础的读者学习和实践。 ... [详细]
  • 2018年9月21日,Destoon官方发布了安全更新,修复了一个由用户“索马里的海贼”报告的前端GETShell漏洞。该漏洞存在于20180827版本的某CMS中,攻击者可以通过构造特定的HTTP请求,利用该漏洞在服务器上执行任意代码,从而获得对系统的控制权。此次更新建议所有用户尽快升级至最新版本,以确保系统的安全性。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • 本文介绍如何在 Android 中自定义加载对话框 CustomProgressDialog,包括自定义 View 类和 XML 布局文件的详细步骤。 ... [详细]
  • 实验九:使用SharedPreferences存储简单数据
    本实验旨在帮助学生理解和掌握使用SharedPreferences存储和读取简单数据的方法,包括程序参数和用户选项。 ... [详细]
author-avatar
勇于明天2015
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有