在做APP时,经常会做到像设置界面,或表单填写这样的界面,实现的方式有多种,比如每一行用UIControl来做,最近做的一个APP里,我还是用UITableViewCell实现的,总结出了一套自认为简单实用的方法,如果您有什么自己惯用的方法,希望在评论中留言呀^_^,互相学习一下!
好了,进入正题,假如我们现在要在APP中实现一个下面这样的表单填写界面:
实现过程:
(1)一共四行,所以创建4个UITableViewCell,下面的按钮不放在UITableView里做,因为每个cell都只用一次,所以我把4个cell都放在一个xib文件中。所以先创建一个FillFormCell.xib,然后在里面拖出4个UITableViewCell,然后按照上面的设计图,排好每个cell里面的子控件,最终如下图所示:
(2)创建一个继承NSObject的类FillFormCellInfo,用这个类来管理FillFormCell.xib中界面上的数据显示。将Fill's Owner设置为FillFormCellInfo,再将4个cell与FillFormCellInfo关联起来,如下:
@interface FillFormCellInfo : NSObject
@property (strong, nonatomic) IBOutlet UITableViewCell *typeCell;
@property (strong, nonatomic) IBOutlet UITableViewCell *reasonCell;
@property (strong, nonatomic) IBOutlet UITableViewCell *timeCell;
@property (strong, nonatomic) IBOutlet UITableViewCell *phoneCell;
@end
(3)在FillFormCellInfo中添加加载xib的方法:
- (void)loadCells
{
[[NSBundle mainBundle]loadNibNamed:@"FillFormCell" owner:self options:nil];
}
这里我想说一下我一直存在的一种误解,我以为FillFormCellInfo中的每一个cell到要用[[[NSBundle mainBundle] loadNibNamed:@"FillFormCell" owner:self options:nil]objectAtIndex:i]赋值一次才可以,于是我愚蠢的写了下面这样的代码:
- (UITableViewCell *)typeCell
{
if (_typeCell!=nil) {
return _typeCell;
}
_typeCell = [[[NSBundle mainBundle]loadNibNamed:kXIBName owner:self options:nil] objectAtIndex:0];
return _typeCell;
}
其实只要执行了一次[[NSBundle mainBundle] loadNibNamed:@"FillFormCell" owner:self options:nil]就会把所有左侧的控件都返回,也就是FillFormCellInfo中的cell就都不为nil了。如果只是简单的这样初始化还没有问题,但是要在这个初始化方法中做事情可能就会得到错误的结果,你可能会把代码写在loadNibNamed的下面,这样你的代码很可能不会执行了。
(4)在FillFormCellInfo中添加返回高度的方法,我把它写成了一个类方法:
+ (float)heightForRow:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return 88.f;
}
return 44.f;
}
(5)创建一个继承UIViewController的类RootViewController,添加一个UITableView的全局变量,然后创建界面:
- (void)loadView
{
self.view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, kMainFrameWidth, kMainFrameHeight)];
self.view.backgroundColor = UIColorFromRGB(0xf4f4f4);
float height = 44*5+10*4+64;
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, kMainFrameWidth, height) style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSelectionStyleNone;
_tableView.bounces = NO;
[self.view addSubview:_tableView];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.backgroundColor = [UIColor lightGrayColor];
[button setTitle:@"提交" forState:UIControlStateNormal];
button.frame = CGRectMake(10, CGRectGetMaxY(_tableView.frame)+15.f, CGRectGetWidth(self.view.frame)-20, 40.f);
[self.view addSubview:button];
[button addTarget:self action:@selector(submitAction:) forControlEvents:UIControlEventTouchUpInside];
}
这里tableview的高度我写了死数据,这个数据也可以在FillFormCellInfo中返回。
(6)在RootViewController中添加一个全局变量FillFormCellInfo,在init中进行初始化,然后实现UITableView的delegate和datasource:
#pragma mark - UITableview delegate and datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 4;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 10.f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [FillFormCellInfo heightForRow:indexPath];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//对于这样的每行cell都不一样的,无需整体刷新,所以也不会存在tableview重用时导致的叠加现象,所以不用弄cellIdentifier,用一个cellInfo包含了所有的cell,在其他任何地方都可以改变cell上的内容,无需刷新
[_fillFormCellInfo loadCells];
if (indexPath.section == 0) {
return _fillFormCellInfo.typeCell;
}
else if (indexPath.section == 1){
return _fillFormCellInfo.timeCell;
}
else if (indexPath.section == 3){
return _fillFormCellInfo.reasonCell;
}
else if (indexPath.section == 2){
return _fillFormCellInfo.phoneCell;
}
return nil;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
(7)给cell的右侧赋值,以表单类型的cell为例,在FillFormCellInfo.h中添加一个属性:
@property (strong, nonatomic) NSString *leaveFormType;
- (void)setLeaveFormType:(NSString *)leaveFormType
{
if (leaveFormType == nil || [leaveFormType isEqualToString:@""]) {
leaveFormType = @"未选择";
}
UILabel *label = (UILabel *)[self.typeCell.contentView viewWithTag:100];
label.text = leaveFormType;
_leaveFormType = leaveFormType;
}
大致的过程就完成了,完整的代码在这github,总结一下这样做的优缺点:
优点:
1、不用再给cell右侧赋值后重新刷新一次UITableView。
2、很容易拿到每一行Cell的值。
3、View与Model与controller完全剥离开了,没有耦合在一起,也无需在controller去动cell里的控件,这样这些UITableViewCell就能够复用到其他界面了。
缺点:
把每个UITableViewCell都当作全局变量保存起来了,如果cell多时会比较消耗内存。
您如果还有什么方法,也来说一下大致思路哟^_^