最近公司项目,经常会是这种界面:一个tableView,然后每个cell有负责一个数据,就像是网站注册用户时需要填写许多用户信息时的界面类似。但是这些cell又不是相同的,可以是既定的label,不可编辑,可以是需要输入的textField,也可能是button弹窗选择,还可能是UISwitch来选择。最后之所以要写文章总结下,是因为我觉得这种界面出现是有规律性的,并且我找到了一点很好写出这种界面的途径。
什么时候会出现这种界面需求呢?当你需要提交的数据是具有多个字段的,并且每一个都是需要用户进行输入的,关键就在于是用户输入的。类似用户信息完善、像51job上添加一个简历这种,当需要提交的东西本身具有多个属性,然后每个属性都需要用户输入的时候,就会是这种界面。像CSDN的编辑简介
看起来似乎很简单,但好像又不是那么简单。最开始遇到的问题就是:cell在划出屏幕再回来就内容消失了,这个问题总结写在另一篇里面了。
想想,最大的问题,其实是每个cell单独写还是使用一个通用的cell通过不同参数来实现不同的界面的问题。一开始我每个cell单独写,真是累死了(我是纯代码写界面的)。故事板里有静态tableview,但是不能为了单独一个界面用故事板吧,用xib可以写tableView的界面吗?拖一个tableView上来,设一个委托,然后没了,每个cell长啥样还是得代码写。最后总结,像这种填写信息的cell,类型是有限的,而且最关键的是基本一个cell负责一个内容,像上面的这张图,第一行是“昵称”和“实名”两个内容,在手机上估计会划分成两行,也就是两个cell里面。这个性质有什么好处呢?就是一个cell只有一个内容,这样可以给cell写一个获取内容的方法,cell就会根据自身的类型得到相应的text,比如:
-(NSString*)text{ if (_type == textField) { return self.textField.text; }else if (_type == button){ return self.button.titleLabel.text; }else if (_type == textView){ return self.textView.text; }else if (_type == switchBtn){ return self.switchBtn.on ? @"是":@"否"; }else if (_type == label){ return self.resultLabel.text; } return nil; }
_type是一个枚举类型:
typedef enum{ textField = 0, button, label, textView, switchBtn, inputNone }contentType;
同样也可以设置text,就是所,你只需要直接使用cell.text = @"中国",cell自己就会去处理了,省去了重复的做判断,简化的感觉太爽了!
上面的枚举每个类型代表了一种cell的承载内容的方式,这样处理过后,这个cell就是一个抽象的更为通用的cell,就是把那些不同的cell全部归结到一种了。很多问题就变得简单了:1、设置字体可以统一设置 2、cell可以批量构建,比如:
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier contentType:(contentType)type title:(NSString*)title text:(NSString*)text placeHolder:(NSString*)placeHolder indexPath:(NSIndexPath*)indexPath;
这是cell的init方法,然后准备好type数组、title数组,text数组等等,当然也可以把这些封装到一个数据类或者字典里,然后再装到数组里,然后根据indexPath取出每个cell需要的参数丢给这个init方法,其他的就不用管了。
当然,我觉得最方便的一点是在提交数据的时候:1、检查数据是否为空,每一项内容都写一遍检查,然后弹窗提示,想想都累,如果使用了通用的cell,那么就可以给cell写一个检查方法,比如
//提交时检测内容是否输入 -(BOOL)checkContent{ //inputNone形式是没有内容输入,所以不做内容是否为空的检查 if(!_isNeedCheck || _type == inputNone){ return YES; } if (self.text == nil || [self.text isEqualToString:@""]) { NSString* alertText = nil; if (self.type == button) { alertText = [NSString stringWithFormat:@"请选择%@",_title]; }else{ alertText = [NSString stringWithFormat:@"请输入%@",_title]; } [SVProgressHUD showErrorWithStatus:alertText]; return NO; } return YES; }
提交是只需要循环保存cell的数组,每个cell调用checkContent方法就好了。
2、数据提交时,比如构建json串,上面图里,肯定就是{“昵称”:@“XXX”,@"实名":@“YYY”,@“职位”:@“ZZZ”}这种形式,那么你需要取到每一个key,再取到对应的value,是不是累死了,如果这些都没有按规律放置(其实规律就是按顺序放进数组,或者按键值存进字典)。而如果使用了通用的cell,并且把这些cell存入了同一个数组,那么只需要循环下这个数组就可以了:
NSMutableDictionary* jsonDic = [NSMutableDictionary dictionary]; for (int i = 0; i<_cellArray.count; i++) { TaskItemCustomCell* cell = [_cellArray objectAtIndex:i]; [jsonDic setValue:cell.text forKey:cell.key]; }
简单的不敢相信!cell.text就是cell上面的内容,cell会根据自身的类型获取对应的text,key是在cell构建的时候放进去的,这也是因为前面说的一个cell只负责一项内容,这样一个cell就对应着提交数据json字典里面的一项键值对。循环一下,把所有cell的内容和相应的键存进字典,一切搞定!
之所以可以这样做,就是这样的界面本身的性质决定,也是由tableView的性质决定的!
而且如果出现了一种新的内容输入形式,只需要给这个cell添加一种新类型就可以了,完全不影响原本的状态。