公司有這么個需求, 要求用戶在線填寫單選形式的答題,效果如下:

這里要注意的是, 每題對應(yīng)的ABCD選項(xiàng)都有對應(yīng)的分?jǐn)?shù), 提交后計(jì)算總分?jǐn)?shù), 每題單選,共10道題, 并且在頁面滑動回之前答過的題后, 要顯示之前已經(jīng)選擇過的選項(xiàng)
當(dāng)然其實(shí)這個簡單的也面, 要實(shí)現(xiàn)并不難, UIScollView + 自定義UIView 容器就可以實(shí)現(xiàn), 公司安卓端就是這么實(shí)現(xiàn)的, 但是缺點(diǎn)也很顯著, 同一個頁面控件太多, 最終導(dǎo)致了項(xiàng)目崩潰
我個人在寫項(xiàng)目的時候, 能用UITableView 的時候盡量不會使用UIScrollView, 所以我第一選擇是使用UITableViewController, 但是使用不分組形式, 因?yàn)橐婚_始看起來每道題目都是類似的界面, 做起來應(yīng)該會很簡單, 原數(shù)據(jù)保存在risk.json中
以下是我一開始的部分代碼
- (void)loadRiskData
{
#pragma mark - Table view data source
if (!_dataArray) {
_dataArray = [NSArray new];
// 解析本地JSON文件獲取數(shù)據(jù),生產(chǎn)環(huán)境中從網(wǎng)絡(luò)獲取JSON
NSString *path = [[NSBundle mainBundle] pathForResource:@"risk" ofType:@"json"];
NSError *error = nil;
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
_dataArray = [JSRiskEvaluateModel objectArrayWithKeyValuesArray:dict[@"question"]];
cellMarkArray = [NSMutableArray array];
for (int i = 0; i < _dataArray.count; i++)
{
cellMarkDic = [NSMutableDictionary dictionary];
[cellMarkDic setObject:@"0" forKey:@"cellMark"];
[cellMarkArray addObject:cellMarkDic];
}
NSLog(@"_dataArray.firstObject = %@ ", _dataArray);
if (error) {
NSLog(@"address.json - fail: %@", error.description);
}
}
}
在這里將risk.json中的數(shù)據(jù)解析出來, 后來做著做著發(fā)現(xiàn)一個問題, 就是我使用的是不分組形式, 一道題里的選項(xiàng),全部放在一個cell中

當(dāng)你點(diǎn)擊一個cell時, 在- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 方法中,沒有辦法區(qū)分你到底是選擇了哪道題, 那么你選擇的那個題目的分?jǐn)?shù)也就無法取出來
所以我又放棄了這種做法, 改為使用分組形式, 一個問題為一個組, 一個選擇項(xiàng)為一個UITableViewCell
可是做著又發(fā)現(xiàn)一個問題, 循環(huán)利用, cell 界面需要將你點(diǎn)擊的那道題目的按鈕變?yōu)檫x中狀態(tài), 這個狀態(tài)是要保存的, 當(dāng)你重新滾回你選擇的題目時,要有之前選中的題目按鈕為選中狀態(tài), 界面不再試一個靜態(tài)的數(shù)據(jù)頁面, 你在重新滾回這個界面時, 從新添加數(shù)據(jù)已經(jīng)不能滿足需求了
為了解決這個問題
-
首先, 我在生成cell時, 不使用循環(huán)生成,
screenshot.png 這樣的話,生成的cell數(shù)據(jù)正確, 但是按鈕點(diǎn)擊的狀態(tài)沒法實(shí)現(xiàn), 所以我使用了字典, 每組一個字典,分別用indexpath.section 作為key, 被選擇的index.row作為value, 然后將字典按順序保存在數(shù)組中


根據(jù)蘋果的特性, 當(dāng)上拉或者下拉UITableViewController, 一個UITableViewCell 即將出現(xiàn)在屏幕上時, 會調(diào)用- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法, 所以我們在這里來判斷他的點(diǎn)擊狀態(tài)
這里取出數(shù)組中對應(yīng)的位置,進(jìn)行重新生成被點(diǎn)中狀態(tài)的cell狀態(tài)
if (indexPath.section == 0)
{
// 如果是字典類, 說明這個組的在數(shù)組中的位置為字典, 說明之前有點(diǎn)擊過這個組的按鈕
if ([self.cellMarkArray[indexPath.section] isKindOfClass:[NSMutableDictionary class]] )
{
UITableViewCell * cell;
NSMutableDictionary *dic = self.cellMarkArray[indexPath.section];
if ([[dic objectForKey:@"0"] isEqualToString:@"1"])
{
cell = [self SelectCellOneView:indexPath andTableView:tableView andRiskModel:riskModel];
}else if ([[dic objectForKey:@"0"] isEqualToString:@"2"])
{
cell = [self SelectCellTwoView:indexPath andTableView:tableView andRiskModel:riskModel];
}else if ([[dic objectForKey:@"0"] isEqualToString:@"3"])
{
cell = [self SelectCellThreeView:indexPath andTableView:tableView andRiskModel:riskModel];
}else if ([[dic objectForKey:@"0"] isEqualToString:@"4"])
{
cell = [self SelectCellForeView:indexPath andTableView:tableView andRiskModel:riskModel];
}else
{
// 普通沒有被選中狀態(tài)
cell = [self nomallCellView:indexPath andTableView:tableView andRiskModel:riskModel];
}
return cell;
}else
{
// 沒有點(diǎn)擊過, 就返回沒選中的cell
// 普通沒有被選中狀態(tài)
UITableViewCell * cell = [self nomallCellView:indexPath andTableView:tableView andRiskModel:riskModel];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
以下是示例第一個選項(xiàng)被點(diǎn)中時, 生成的cell狀態(tài)
- (UITableViewCell *)SelectCellOneView:(NSIndexPath *)indexPath andTableView:(UITableView *)tableView andRiskModel:(JSRiskEvaluateModel *)riskModel
{
if (indexPath.row == 0)
{
JSGotoRiskQuestionTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:questionTitle];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.questionTitleStr = riskModel.questionTitle;
return cell;
}else if (indexPath.row == 1)
{
// JSGotoRiskCell *cell = [tableView dequeueReusableCellWithIdentifier:question];
JSGotoRiskCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([JSGotoRiskCell class]) owner:nil options:nil] lastObject];
}
cell.line.hidden = YES;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.questionLabel.text = riskModel.questionA;
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_a_on"] forState:UIControlStateNormal];
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_a"] forState:UIControlStateSelected];
[cell.questionBtn setSelected:YES];
return cell;
}else if (indexPath.row == 2)
{
// JSGotoRiskCell *cell = [tableView dequeueReusableCellWithIdentifier:question];
JSGotoRiskCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([JSGotoRiskCell class]) owner:nil options:nil] lastObject];
}
cell.line.hidden = YES;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.questionLabel.text = riskModel.questionB;
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_b_on"] forState:UIControlStateNormal];
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_b"] forState:UIControlStateSelected];
return cell;
}else if (indexPath.row == 3)
{
// JSGotoRiskCell *cell = [tableView dequeueReusableCellWithIdentifier:question];
JSGotoRiskCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([JSGotoRiskCell class]) owner:nil options:nil] lastObject];
}
cell.line.hidden = YES;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.questionLabel.text = riskModel.questionC;
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_c_on"] forState:UIControlStateNormal];
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_c"] forState:UIControlStateSelected];
return cell;
}else if (indexPath.row == 4)
{
// JSGotoRiskCell *cell = [tableView dequeueReusableCellWithIdentifier:question];
JSGotoRiskCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([JSGotoRiskCell class]) owner:nil options:nil] lastObject];
}
if (indexPath.section == 8)
{
cell.line.hidden = YES;
}else
{
cell.line.hidden = NO;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.questionLabel.text = riskModel.questionD;
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_d_on"] forState:UIControlStateNormal];
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_d"] forState:UIControlStateSelected];
return cell;
}else
{
// JSGotoRiskCell *cell = [tableView dequeueReusableCellWithIdentifier:question];
JSGotoRiskCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([JSGotoRiskCell class]) owner:nil options:nil] lastObject];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.questionLabel.text = riskModel.questionE;
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_e_on"] forState:UIControlStateNormal];
[cell.questionBtn setImage:[UIImage imageNamed:@"icon_e"] forState:UIControlStateSelected];
return cell;
}
}
有個注意點(diǎn)就是數(shù)組的插入不要使用insertObject, 我最后使用了repalceObjectAtIndex的方式將字典存放在對應(yīng)的數(shù)組位置中, 因?yàn)槲野l(fā)現(xiàn)使用insert的方式, 偶爾在來回滾動的過程中, 生成數(shù)組時有時會取不出對應(yīng)的字典, 導(dǎo)致后面的cell重現(xiàn)變?yōu)闆]有選中狀態(tài)
單選實(shí)現(xiàn)的文件已經(jīng)放在了gitHub 上, 小家可以來這里下載問卷調(diào)查(單選)
文件暫時還沒有整理, 有點(diǎn)亂,后期有時間我會再整理, 但是不影響使用, 打開可直接運(yùn)行, 希望對小伙伴們有用
