OCiOS开发:表格视图实现腾讯好友列表展开收缩效果
来源:互联网 发布:知乎阿里云免费开通码 编辑:程序博客网 时间:2024/06/06 03:38
前言
这几天刚刚给学生讲到了表格视图的使用,有学生问我,如果要实现类似于腾讯好友列表展开收缩的效果该怎么实现呢?以前我写过有关这样效果的demo,但是一直没有发表成文,今天刚好有时间,于是写出来,分享给各位,当然要实现这种效果方法还是有很多,这里就讲解下我的实现方式,不到之处,还往各位提点建议,我会及时改进。
效果
为了简化数据,所以每个分组里面的好友数据都是一样的。
实现思路
1、用一个字典来判断,将section作为key,如果字典对应key有值,则展开组,反之则关闭组。
2、自定义头部视图,并且给头部视图添加点击事件(UITapGestureRecognizer
)监测用户点击分组。
3、在主页为表视图创建头部视图的时候,为其设置tag值,其值为当前所在的组(section),并且在自定义头部视图类中,通过委托模式,将其tag值传递到主页,为其获取到对应头部视图的section
,设为字典key。
4、涉及技术:委托模式、自定义单元格、自定义头部视图、plist文件读取、点击手势以及协议传值。
数据处理
好友列表展示的数据,我已预先存到plist文件中,包括图片素材,也一并导入了工程,如下所示:
素材下载地址:http://download.csdn.net/detail/hierarch_lee/9412991
代码实现
由于代码相对较简单,并且关键部分我也详细注明了代码解释,因此,就不做具体的讲解。
涉及文件
1、LHY_HomeViewController:主页,继承于UIViewController,用于展示好友列表。
2、LHY_FriendsListCell:自定义单元格,继承于UITableViewCell,用于布局好友列表信息;
3、LHY_HeaderView:自定义头部视图,继承于UITableViewHeaderFooterView,用于布局分组显示数据;
代码块1:为主页添导航栏,这里我是手动创建UIWindow,首先在Info.plist将Main字段删除,然后在AppDelegate.m文件中,导入LHY_HomeViewController,添加如下代码:
- AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. LHY_HomeViewController *lhyVc = [[LHY_HomeViewController alloc] init]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:lhyVc]; _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; _window.backgroundColor = [UIColor blackColor]; _window.rootViewController = nav; [_window makeKeyAndVisible]; return YES;}
代码块2:自定义单元格,LHY_FriendsListCell,主要布局好友信息包括头像、昵称以及签名,具体实现如下:
- LHY_FriendsListCell.h
#import <UIKit/UIKit.h>@interface LHY_FriendsListCell : UITableViewCell@property (strong, nonatomic) UIImageView *headPortraitImageView; /**< 头像 */@property (strong, nonatomic) UILabel *nicknameLabel; /**< 昵称 */@property (strong, nonatomic) UILabel *signatureLabel; /**< 签名 */@end
- LHY_FriendsListCell.m
#import "LHY_FriendsListCell.h"@implementation LHY_FriendsListCell- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { // 加载视图 [self.contentView addSubview:self.headPortraitImageView]; [self.contentView addSubview:self.nicknameLabel]; [self.contentView addSubview:self.signatureLabel]; } return self;}#pragma mark *** Getters ***- (UIImageView *)headPortraitImageView { if (!_headPortraitImageView) { _headPortraitImageView = [[UIImageView alloc] init]; _headPortraitImageView.bounds = CGRectMake(0, 0, 60, 60); _headPortraitImageView.center = CGPointMake(40, 40); // 设置文本现实模式 _headPortraitImageView.contentMode = UIViewContentModeScaleAspectFit; // 设置圆角 _headPortraitImageView.layer.cornerRadius = 30; // 设置图层超出父视图部分不显示 _headPortraitImageView.layer.masksToBounds = YES; } return _headPortraitImageView;}- (UILabel *)nicknameLabel { if (!_nicknameLabel) { _nicknameLabel = [[UILabel alloc] initWithFrame:CGRectMake(80, 5, 310, 30)]; _nicknameLabel.font = [UIFont boldSystemFontOfSize:18]; _nicknameLabel.textColor = [UIColor redColor]; } return _nicknameLabel;}- (UILabel *)signatureLabel { if (!_signatureLabel) { _signatureLabel = [[UILabel alloc] initWithFrame:CGRectMake(80, 50, 310, 20)]; _signatureLabel.font = [UIFont systemFontOfSize:15]; } return _signatureLabel;}@end
代码块3:自定义头部视图,LHY_HeaderView,本类主要布局组标题以及指示(展开/关闭)控件,其次,通过添加点击手势结合委托模式,传递tag值。
- LHY_HeaderView.h
#import <UIKit/UIKit.h>@class LHY_HeaderView;// 协议声明@protocol LHY_HeaderViewDelegate <NSObject>- (void)lhyHeaderView:(LHY_HeaderView *)lhyHeaderView didSelectedWithTag:(NSInteger)tag;@end@interface LHY_HeaderView : UITableViewHeaderFooterView@property (nonatomic, strong) UILabel *sectionTitleLabel; /**< 组标题 */@property (nonatomic, strong) UIImageView *indictorImageView; /**< 指示图片 */@property (nonatomic, weak) id <LHY_HeaderViewDelegate> delegate; /**< 代理 */@end
- LHY_HeaderView.m
#import "LHY_HeaderView.h"@implementation LHY_HeaderView- (instancetype)initWithReuseIdentifier:(nullable NSString *)reuseIdentifier { if (self = [super initWithReuseIdentifier:reuseIdentifier]) { self.contentView.backgroundColor = [UIColor clearColor]; self.layer.borderWidth = 0.34; self.layer.borderColor = [UIColor lightGrayColor].CGColor; // 加载控件 [self.contentView addSubview:self.indictorImageView]; [self.contentView addSubview:self.sectionTitleLabel]; // 添加点击手势 UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToTapGesture:)]; [self addGestureRecognizer:tapGesture]; } return self;}#pragma mark *** Gestures ***- (void)respondsToTapGesture:(UITapGestureRecognizer *)gesture { // 判断代理是否存并且遵守协议,如果满足条件,则让代理执行协议方法,并且将对应组以及tag值传递给代理; if (_delegate && [_delegate conformsToProtocol:@protocol(LHY_HeaderViewDelegate)]) { [_delegate lhyHeaderView:self didSelectedWithTag:self.tag]; }}#pragma mark *** Getters ***- (UIImageView *)indictorImageView { if (!_indictorImageView) { _indictorImageView = [[UIImageView alloc] init]; _indictorImageView.bounds = CGRectMake(0, 0, 20, 20); _indictorImageView.center = CGPointMake(15, 22); } return _indictorImageView;}- (UILabel *)sectionTitleLabel { if (!_sectionTitleLabel) { _sectionTitleLabel = [[UILabel alloc] init]; _sectionTitleLabel.bounds = CGRectMake(0, 0, 200, 30); _sectionTitleLabel.center = CGPointMake(CGRectGetMaxX(self.indictorImageView.frame) + CGRectGetMidX(_sectionTitleLabel.bounds) + 10, 22); _sectionTitleLabel.font = [UIFont boldSystemFontOfSize:18]; } return _sectionTitleLabel;}@end
代码块4:加载主页,LHY_HomeViewController,本类主要配置表格视图显示,以及处理组展开/关闭状态。
- LHY_HomeViewController.h
#import <UIKit/UIKit.h>@interface LHY_HomeViewController : UIViewController@end
- LHY_HomeViewController.m
#import "LHY_HomeViewController.h"#import "LHY_HeaderView.h"#import "LHY_FriendsListCell.h"static NSString *const kLHY_ViewControllerTitle = @"好友列表";static NSString *const kReusableCellIdentifier = @"a1b1c1";static NSString *const kHeaderFooterViewReuseIdentifier = @"a2b2c2";@interface LHY_HomeViewController () <UITableViewDataSource, UITableViewDelegate, LHY_HeaderViewDelegate>{ NSArray *_sectionTitles; /**< 分组标题集合 */ NSArray *_friendsListInfo; /**< 好友信息集合 */ NSMutableDictionary *_openDict; /**< 用于设置当前分组展开或关闭 */}@property (nonatomic, strong) UITableView *tableView; /**< 表格视图 */- (void)initializeDataSource; /**< 初始化数据源 */- (void)initializeUserInterface; /**< 初始化用户界面 */@end@implementation LHY_HomeViewController- (void)viewDidLoad { [super viewDidLoad]; [self initializeDataSource]; [self initializeUserInterface];}#pragma mark *** Initialize methods ***- (void)initializeDataSource { // 初始化分组数据 _sectionTitles = @[@"同事", @"家人", @"朋友", @"同学", @"陌生人", @"黑名单"]; // 根据plist文件获取好友列表数据 NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"FriendsList" ofType:@"plist"]; _friendsListInfo = [NSArray arrayWithContentsOfFile:plistPath];}- (void)initializeUserInterface { self.title = kLHY_ViewControllerTitle; // 关闭系统自动偏移 self.automaticallyAdjustsScrollViewInsets = NO; self.view.backgroundColor = [UIColor whiteColor]; // 加载表格视图 [self.view addSubview:self.tableView];}#pragma mark *** <UITableViewDataSource, UITableViewDelegate> ***// 设置组数- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // 返回分组数据集合的个数 return _sectionTitles.count;}// 设置行数- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // 返回好友列表信息集合的个数 return _friendsListInfo.count;}// 设置单元格- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { LHY_FriendsListCell *cell = [tableView dequeueReusableCellWithIdentifier:kReusableCellIdentifier forIndexPath:indexPath]; // 超出父视图不显示,如果不将其值设为YES(默认为NO),那么现实在表格视图上的数据会出现重叠的bug。 cell.layer.masksToBounds = YES; // 获取值 NSString *nickName = _friendsListInfo[indexPath.row][@"nickName"]; NSString *headPortrait = _friendsListInfo[indexPath.row][@"headPortrait"]; NSString *signature = _friendsListInfo[indexPath.row][@"context"]; // 赋值控件 cell.nicknameLabel.text = nickName; cell.signatureLabel.text = signature; cell.headPortraitImageView.image = [UIImage imageNamed:headPortrait]; return cell;}// 设置行高- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // 根据当前组获取字典key NSString *key = [NSString stringWithFormat:@"%ld", indexPath.section]; // 判断如果字典对应key是否有值,如果有值,说明当前组展开,返回 80 高度;否则为关闭,返回 0 高度; if ([_openDict objectForKey:key]) { return 80; }else { return 0; }}// 设置组高- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 44;}// 自定义头部视图- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // 创建头部视图 // 头部视图重用 LHY_HeaderView *lhyHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kHeaderFooterViewReuseIdentifier]; // 设置代理 lhyHeaderView.delegate = self; // 配置视图显示 lhyHeaderView.sectionTitleLabel.text = _sectionTitles[section]; lhyHeaderView.indictorImageView.image = [UIImage imageNamed:@"flag.png"]; // 设置tag值 lhyHeaderView.tag = section; // 根据字典对应key(section)是否有值来判断当前组应该展开还是收缩 // 如果有值,则说明应该展开组,无值则应该关闭组 NSString *key = [NSString stringWithFormat:@"%ld", section]; // 通过动画效果实现展开与关闭指示状态的显示 [UIView animateWithDuration:0.4 animations:^{ // 如果展开,则将指示图片旋转45°,箭头向下,意为展开; // 如果关闭,则移除transform属性,回复原样,箭头向右,意为关闭; lhyHeaderView.indictorImageView.transform = [_openDict objectForKey:key] ? CGAffineTransformMakeRotation(M_PI_2) : CGAffineTransformIdentity; }]; return lhyHeaderView;}#pragma mark *** LHY_HeaderViewDelegate ***- (void)lhyHeaderView:(LHY_HeaderView *)lhyHeaderView didSelectedWithTag:(NSInteger)tag { // 判断字典是否存在,如果不存在,则新建; // 如果对一个未初始化的可变字典作数据操作,将会导致奔溃; if (!_openDict) { _openDict = [NSMutableDictionary dictionary]; } // 获取tag值,并将其作为字典key NSString *key = [NSString stringWithFormat:@"%ld", tag]; // 模拟展开与关闭 // 判断当前组是否有值,有值则移除对应key-value对,无值则设置key-value对。 if (![_openDict objectForKey:key]) { [_openDict setObject:key forKey:key]; }else{ [_openDict removeObjectForKey:key]; } // 刷新表格视图指定组 [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:tag] withRowAnimation:UITableViewRowAnimationFade];}#pragma mark *** Getters ***- (UITableView *)tableView { if (!_tableView) { _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - 64) style:UITableViewStylePlain]; // 设置代理 _tableView.delegate = self; // 设置数据源 _tableView.dataSource = self; // 设置尾部视图(此设置可解决当表格视图在屏幕能完全展示数据,并且有多余空间情况下出现分割线的问题) _tableView.tableFooterView = [[UIView alloc] init]; // 注册单元格 [_tableView registerClass:[LHY_FriendsListCell class] forCellReuseIdentifier:kReusableCellIdentifier]; // 注册头部视图 [_tableView registerClass:[LHY_HeaderView class] forHeaderFooterViewReuseIdentifier:kHeaderFooterViewReuseIdentifier]; } return _tableView;}@end
到了这一步,运行工程,你将会看到上述展示的效果。如果还有朋友不太熟悉思路,欢迎加Q:894416347,填好备注信息,或留言,一起探讨。
- OCiOS开发:表格视图实现腾讯好友列表展开收缩效果
- Android_QQ好友列表实现---ExpandableListView可展开列表视图
- 使用RecyclerView 简单实现QQ好友列表展开效果
- (二十八)QQ好友列表的展开收缩
- jquery实现:列表展开与收缩
- 表格展开与收缩
- Android中实现类似qq好友列表展开收起的效果
- OCiOS开发:集合视图 UICollectionView
- jquery展开收缩列表
- Android列表收缩与展开仿QQ好友列表(非常详细,附源码)
- Android列表收缩与展开仿QQ好友列表(非常详细,附源码)
- QQ列表的收缩展开,带动画效果
- 标题收缩展开效果
- 收缩和展开效果
- JS 收缩 展开效果
- jQuery收缩展开效果
- JS收缩展开效果
- jQuery实现DIV层的收缩展开效果
- 射频通信原理
- 初探JSP
- Gradle DSL method not found: 'android()
- 第五天,uiscorllview的滚动和缩放,以及代理调用,定时器,对话框
- Linux tar 命令
- OCiOS开发:表格视图实现腾讯好友列表展开收缩效果
- leetcode笔记:Range Sum Query - Immutable
- Android_程序退出_关闭所有activity代码
- JSONModel简介(一)——读取并转化简单的本地JSON文件
- 响应函数(响应机制)——高版本与低版本之间的差异!!
- OC - @property与setter,getter方法
- TranslateAnimation详解
- jquyer 表单 屏蔽回车,自动跳转到下个文本框!
- 微信公共号开发简单入门