TableView之基础模式

UITableView

这个组件大家应该都是熟的不能再熟了,它几乎存在于所有的APP中,因此在这里讲这个是有点过于啰嗦。不过呢,为了作为一个比较,还是来简单的说一下,不想看的就不用看了,就当我来充一下篇幅了。

UITableView,用于展示单一列数据的组件,它继承自UIScrollView,因此它也具有滚动的能力。
Table主要是由多行(Cell)子视图所组成,对于我们开发一个Table表视图来说,多的就是在做cell视图的定制和管理,于是就有了各种各样的写法。。。。

  • UITableViewDataSource
    TableView的数据源协议,用于设定分组数量、行的数量、每行的视图等等,它作为数据提供方,是在开发的时候必不可少需要实现的部分。
  • UITableViewDelegate
    TableView的管理操作协议,用于管理表视图上各行的状态、分组的头尾诗图和各种事件的分发触发等。

写一个简单的TableView

  • 1. 添加一个TableView
1
@property (nonatomic, strong) UITableView *tableView;

初始化TableView,并添加代理,然后添加到当前的视图中。

  • 2. 添加数据源
1
@property (nonatomic, strong) NSMutableArray <NSArray <NSDictionary *> *> *datas;

假装这是请求到了数据吧,一般都是固定的数据或者动态请求、生成的数据。

  • 3. 设置分组数
1
2
3
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.datas.count;
}
  • 4. 设置每个分组的行数
1
2
3
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.datas objectAtIndex:section] count];
}
  • 5. 设置每个Cell的内容

其实我们花费更多的工作是在这里

1
2
3
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
....
}

其实我们花费更多的工作是在这里,就是为了控制不同行的状态和显示内容的丰富。
在这里我假定我们有几种不同类型的cell,都是根据数据源中的type字段来控制,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
NSDictionary *data = [[self.datas objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([data[@"type"] isEqualToString:@"text"]) {
static NSString *textCellReusedIdentifier = @"com.auu.textCellReusedIdentifier";
TextCell *cell = [tableView dequeueReusableCellWithIdentifier:textCellReusedIdentifier];
if (!cell) {
cell = [[TextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:textCellReusedIdentifier];
}
cell.data = data;
return cell;
} else if ([data[@"type"] isEqualToString:@"image"]) {
static NSString *imageCellReusedIdentifier = @"com.auu.imageCellReusedIdentifier";
ImageCell *cell = [tableView dequeueReusableCellWithIdentifier:imageCellReusedIdentifier];
if (!cell) {
cell = [[ImageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:imageCellReusedIdentifier];
}
cell.data = data;
return cell;
} else if ([data[@"type"] isEqualToString:@"input"]) {
static NSString *inputCellReusedIdentifier = @"com.auu.inputCellReusedIdentifier";
InputCell *cell = [tableView dequeueReusableCellWithIdentifier:inputCellReusedIdentifier];
if (!cell) {
cell = [[InputCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:inputCellReusedIdentifier];
}
cell.data = data;
return cell;
}
return nil;

我们的定义的Cell在这里,简单看看就行:

1
2
3
4
5
6
7
8
9
10
11
12
13
@interface BaseCell : UITableViewCell
@property (nonatomic, strong) NSDictionary *data;
@end
@implementation BaseCell @end
@interface TextCell : BaseCell @end
@implementation TextCell @end
@interface ImageCell : BaseCell @end
@implementation ImageCell @end
@interface InputCell : BaseCell @end
@implementation InputCell @end
  • 6. 控制高度
    至此内容内容显示算是做完了,下面来控制每行的高度,实际开发肯定是根据不同的数据类型通过计算或者固定元素固定高度的方式给出一个合理的高度的,这里就省点写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *data = [[self.datas objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([data[@"type"] isEqualToString:@"text"]) {
// 计算一番.....
return 44.0;
} else if ([data[@"type"] isEqualToString:@"image"]) {
// 计算一番.....
return 108.0;
} else if ([data[@"type"] isEqualToString:@"input"]) {
// 计算一番.....
return 64.0;
}
return 44.0;
}
  • 7. 响应事件

现在这个表视图算是按照我们的预想展示出来了,但是光展示又没啥用,还得响应事件啊:

1
2
3
4
5
6
7
8
9
10
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *data = [[self.datas objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([data[@"type"] isEqualToString:@"text"]) {
NSLog(@"我选中了文本行,我需要做些事情");
} else if ([data[@"type"] isEqualToString:@"image"]) {
NSLog(@"我选中了图片行,我需要做些事情");
} else if ([data[@"type"] isEqualToString:@"input"]) {
NSLog(@"我选中了输入行,我需要做些事情");
}
}

然而事实上是,我们更多的需求可能还会需要动态的更新数据、更新视图等等,这些这次就不说了。

再白话两句

由上面可以看出,其实所有的工作都是在每一行的类型判断上了,不管是添加一个cell,还是设置高度,还有事件的响应等等,这只是一个简单的例子,如果我们增加一些增删的操作来试试呢,是不是该哭了? (●゚ω゚●)
但是这都是套路的,为啥我不能在在一个判断的地方就把左右的事情都做了呢?为啥还要分开去做呢?苹果这样是为了让我们有更多的发挥空间来处理各种视图定制和事件处理,但是有的时候,简单点,统一做了也不失为一个好办法。