同一界面加载不同的UITableViewCell,如表单或者设置界面

来源:互联网 发布:艾学通排课软件 编辑:程序博客网 时间:2024/06/05 05:11

在做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;

在typeCell中将右侧的label的tag设置为100,以便拿到这个label,重写leaveFormType的set方法:

- (void)setLeaveFormType:(NSString *)leaveFormType{    if (leaveFormType == nil || [leaveFormType isEqualToString:@""]) {        leaveFormType = @"未选择";    }    UILabel *label = (UILabel *)[self.typeCell.contentView viewWithTag:100];    label.text = leaveFormType;        _leaveFormType = leaveFormType;}

如此,拿到type的值也就容易了。


大致的过程就完成了,完整的代码在这github,总结一下这样做的优缺点:

优点:

1、不用再给cell右侧赋值后重新刷新一次UITableView。

2、很容易拿到每一行Cell的值。

3、View与Model与controller完全剥离开了,没有耦合在一起,也无需在controller去动cell里的控件,这样这些UITableViewCell就能够复用到其他界面了。

缺点:

把每个UITableViewCell都当作全局变量保存起来了,如果cell多时会比较消耗内存。


您如果还有什么方法,也来说一下大致思路哟^_^

0 0
原创粉丝点击