在开发 iOS 应用时,基本都会遇到个人中心、设置、详情信息等页面,这里截取了某应用的详情编辑页面和个人中心页面,如下:
我们以页面结构的角度考虑这两个页面的共同点:
如果觉着以一个应用为例子不具有说服力,那么大家可以打开各自手机上的应用看一下(比如微信、淘宝等)。 根据我个人的项目开发经验,基本上每个应用都会有拥有一些具有上述共同点(一个或多个)的页面。
那么这类页面应该怎么编写才能保证规范性以及灵活性?本文就是讲述了这一类页面应该如何编写。
提示:阅读本文时,建议参考 本文的demo,本文的demo提供了 Objective-C 版本和 Swift 版本。
使用 Xib 对这类页面进行可视化编辑是一种不错的选择,但这类方案也有部分缺点,比如:
Xib 确实是一种不错的方法,简单方便,但从上面分析可看出 Xib 也存在一些问题。本文对 Xib 不再进行深入讨论,一是个人喜好,另外主要原因是工作中对 Xib 使用并不多, 所以可能有些东西尚未深入研究,无法过多的讨论。
有些同学写这类页面时可能会选择一个不怎么好的方案:将页面所有的 View 作为 UIScrollView 的子View。
这样编写这类页面时,controller 的代码基本类似于下面这样:
- (void)viewDidLoad {
[super viewDidLoad];
[self loadSubviews];
}
- (void)loadSubviews {
// scrollView 作为所有子View的容器
_scollView = [[UIScrollView alloc] init];
[self.view addSubview:_scrollView];
_view1 = [[UIView alloc] init];
[_scrollView addSubview:_view1];
// 添加其余子View,并为每个View设置约束(如果不使用约束,则也需要在 viewWillLayoutSubviews 方法中为各个View设置 Frame)
// 此外,还要定义各类点击行为和点击效果。
}
根据经验来看,这类写法基本不可取,主要原因有以下几点:
所以,对于随业务需求修改极有可能导致页面布局和内容变化的页面,我们不能使用 UIScrollView 来管理子View。那么什么时候可以使用 UIScrollView 来管理页面中的视图呢? 这里给出两个条件:
当满足这两个条件时,建议采用 UIScrollView 来管理页面中的视图,这也是最简单的方案,如下图某应用的反馈页面:
另一种方案是将页面中每一行看作为 UITableView 的一个 Cell,通过 UITableView 来组织这类页面中的各个视图。
下面让我们以 demo 中的页面为例,来看一下这种方案写出的 Controller 代码是什么样子的:
(1) 先介绍一下 demo 页面,如下图:
整个页面是以 UITableView 实现的,分为两个 section:cell1(类型为 MCDemoCell1)和 cell2(类型为 MCDemoCell2) 为 section1,cell3(类型为 MCDemoCell3) 为 section2。
(2) 首先,我们要新建一个 UITableView,然后为其设置 dataSource 和 delegate,以及确定其布局,代码如下:
#pragma mark - Life cycle.
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"MultiCellTypeTableViewOC";
self.view.backgroundColor = [UIColor whiteColor];
[self loadSubviews];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
_tableView.frame = self.view.bounds; // 对 tableView 布局
}
#pragma mark - Load views.
- (void)loadSubviews {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.delegate = self; // 设置 tableView 的 delegate
_tableView.dataSource = self; // 设置 tableView 的 dataSource
[self.view addSubview:_tableView];
}
(3) 实现 UITableViewDataSource 的方法:
#pragma mark - UITableViewDataSource.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// 返回 section 的数量,本例中为 2
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// 根据 section 区分有几个 cell
if (section == 0) {
return 2;
} else {
return 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
// 根据 indexPath 获取不同的 Cell
if (indexPath.section == 0) {
if (indexPath.row == 0) {
cell = [self getCell1];
} else {
cell = [self getCell2];
}
} else {
cell = [self getCell3];
}
return cell;
}
上述代码中获取不同 Cell 的方法是私有方法,主要就是创建一个类型的 Cell,然后为该 Cell 进行配置数据,下面是 getCell2 的例子:
- (UITableViewCell *)getCell2 {
MCDemoCell2 *cell = [[MCDemoCell2 alloc] init];
cell.titleLabel.text = @"cell2";
cell.contentLabel.text = @"cell2's content";
cell.rightSwitchButton.on = YES;
cell.delegate = self;
return cell;
}
(4) 实现 UITableViewDelegate 的方法:
#pragma mark - UITableViewDelegate.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 20;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat cellHeight = 0;
// 根据 indexPath 获取不同 Cell 的高度
if (indexPath.section == 0) {
cellHeight = 44.0;
} else {
cellHeight = 80.0;
}
return cellHeight;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// 如果选中不同 cell 的动作不一致,则需要使用判断执行对应的操作
if (indexPath.section == 0) {
if (indexPath.row == 0) {
NSLog(@"cell1 selected");
} else {
NSLog(@"cell2 selected");
}
} else {
NSLog(@"cell3 selected");
}
}
这种方案的详细代码见 demo 的 OldViewController。
本文未结束,敬请期待下篇。
谈谈iOS开发如何写个人中心这类页面--静态tableView页面的编写(中)
谈谈iOS开发如何写个人中心这类页面--静态tableView页面的编写(下)
本文来自网易实践者社区,经作者白天宇授权发布。