前面几篇文章记录了UITableView的一些特性和使用,今天突然想要写一篇关于UITableView的个人理解。
UITableView是一个列表控件,但是在开发中,列表的样子是千奇百怪。每个产品都希望自己设计的app界面是独一的,有这自己的元素。比如:微信的朋友圈列表(动态高度),QQ好友列表(点击展示隐藏分组),京东的物品分类列表(瀑布流)等等。。。
面对这样复杂多变的设计,作为一个开发人员,要有自己的一套对于界面的理解,也就是对于控件的理解,这里我就以QQ好友列表为例简单说一下我对于复杂列表界面的开发思路。
下面是代码,在代码中有必要的注释。
#import "ViewController.h"
@interface ViewController ()
{
UITableView *table;
//用于列表展示的数据源
NSMutableArray *dataSource;
//保存列表数据的数据源
NSMutableArray *data;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self createDataSource];
[self createTableView];
}
//s初始化数据源
- (void)createDataSource{
NSArray *array = @[@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"],
@[@"111",@"222",@"333",@"444",@"555",@"666",@"777"]];
data = [NSMutableArray arrayWithArray:array];
dataSource = [NSMutableArray arrayWithCapacity:0];
for (int i=0; i<10; i++) {
NSDictionary *dic = @{@"isOpen":@"open", @"data":@[]};
[dataSource addObject:dic];
}
}
//创建视图
- (void)createTableView{
//创建并设置位置大小和风格形式
//由于QQ分组在展开分组好友滚动时有组头定位,也就是在下一个组头滚动到tableView的最上方时当前的组头一直在最上方位置,所以即使是分组的列表,UITableView的style也还是UITableViewStylePlain
table = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
//设置代理
table.delegate = self;
table.dataSource = self;
//设置纵横滑块不显示
table.showsVerticalScrollIndicator = NO;
table.showsHorizontalScrollIndicator = NO;
[self.view addSubview:table];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return dataSource.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSDictionary *dic = dataSource[section];
NSArray *array = [dic objectForKey:@"data"];
return array.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 40;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 30;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
return 0.01;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
//设置分组的头视图
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 30)];
view.backgroundColor = [UIColor yellowColor];
view.tag = section;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 100, 20)];
label.text = [NSString stringWithFormat:@"第%ld组",section];
label.userInteractionEnabled = YES;
[view addSubview:label];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(headClick:)];
[view addGestureRecognizer:tap];
return view;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
return nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
NSDictionary *dic = dataSource[indexPath.section];
NSArray *array = [dic objectForKey:@"data"];
cell.textLabel.text = array[indexPath.row];
return cell;
}
- (void)headClick:(UITapGestureRecognizer *)tap{
UIView *view = tap.view;
NSInteger section = view.tag;
NSDictionary *dic = dataSource[section];
NSString *isOpen = [NSString stringWithFormat:@"%@",[dic objectForKey:@"isOpen"]];;
BOOL ok = [isOpen isEqualToString:@"open"];
if (ok) {
[dataSource removeObjectAtIndex:section];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:0];
NSArray *array = data[section];
[dict setObject:@"close" forKey:@"isOpen"];
[dict setObject:array forKey:@"data"];
[dataSource insertObject:dict atIndex:section];
}else{
[dataSource removeObjectAtIndex:section];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:0];
NSArray *array = @[];
[dict setObject:@"open" forKey:@"isOpen"];
[dict setObject:array forKey:@"data"];
[dataSource insertObject:dict atIndex:section];
}
[table reloadData];
}
@end
由于是写一个例子,所以没有去自定义cell,没有做数据model。只是简单实现需求。在上面的代码实例中可以看到,对于列表的展示和隐藏我是通过控制数据源实现的。通过数据源的变化再刷新视图。
总结:UITableView是一个列表视图,对于列表视图有一个很重要的特点就是它的展示和数据源有很大的关系,比如列表的多少,比如列表的展示风格等等。这些特性就是我们开发复杂界面的关键,对于列表的设计在很多时候可以通过改动数据源实现。就像上面的例子一样,通过点击修改数据源中对应分组中的数据来实现每组中cell的个数,从而实现展示和隐藏。
同样的对于微信的朋友圈列表,也是通过改变数据源的数据进行的,当评论时数据源发生变化,获取到新的数据源后刷新界面。
虽然UITableView是一个视图控件,但是对于它的操作并不是简单的使用属性之类的设置,面对复杂多变的设计,灵活运用数据源才是最简单的方法。这一点不仅仅是在UITableView的使用上,在很多地方都是一样的,一个app的开发,界面不管有多少,无非就是一些控件的组合,真正多变的是数据,对于数据的处理才是重点。
(上面是一些本人的个人理解,不喜勿喷)