单选问答题实现思路(UITableView方式)

公司有这么个需求, 要求用户在线填写单选形式的答题,效果如下:

单选问答题实现思路(UITableView方式)_第1张图片
风险评估页面

这里要注意的是, 每题对应的ABCD选项都有对应的分数, 提交后计算总分数, 每题单选,共10道题, 并且在页面滑动回之前答过的题后, 要显示之前已经选择过的选项

当然其实这个简单的也面, 要实现并不难, UIScollView + 自定义UIView 容器就可以实现, 公司安卓端就是这么实现的, 但是缺点也很显著, 同一个页面控件太多, 最终导致了项目崩溃

我个人在写项目的时候, 能用UITableView 的时候尽量不会使用UIScrollView, 所以我第一选择是使用UITableViewController, 但是使用不分组形式, 因为一开始看起来每道题目都是类似的界面, 做起来应该会很简单, 原数据保存在risk.json中

以下是我一开始的部分代码

- (void)loadRiskData
{
#pragma mark - Table view data source
    if (!_dataArray) {
        _dataArray = [NSArray new];
        // 解析本地JSON文件获取数据,生产环境中从网络获取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中的数据解析出来, 后来做着做着发现一个问题, 就是我使用的是不分组形式, 一道题里的选项,全部放在一个cell中


单选问答题实现思路(UITableView方式)_第2张图片
screenshot.png

当你点击一个cell时, 在- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 方法中,没有办法区分你到底是选择了哪道题, 那么你选择的那个题目的分数也就无法取出来

所以我又放弃了这种做法, 改为使用分组形式, 一个问题为一个组, 一个选择项为一个UITableViewCell
可是做着又发现一个问题, 循环利用, cell 界面需要将你点击的那道题目的按钮变为选中状态, 这个状态是要保存的, 当你重新滚回你选择的题目时,要有之前选中的题目按钮为选中状态, 界面不再试一个静态的数据页面, 你在重新滚回这个界面时, 从新添加数据已经不能满足需求了

为了解决这个问题

  1. 首先, 我在生成cell时, 不使用循环生成,


    单选问答题实现思路(UITableView方式)_第3张图片
    screenshot.png
  2. 这样的话,生成的cell数据正确, 但是按钮点击的状态没法实现, 所以我使用了字典, 每组一个字典,分别用indexpath.section 作为key, 被选择的index.row作为value, 然后将字典按顺序保存在数组中

单选问答题实现思路(UITableView方式)_第4张图片
Snip20170327_2.png

单选问答题实现思路(UITableView方式)_第5张图片
Snip20170327_1.png

根据苹果的特性, 当上拉或者下拉UITableViewController, 一个UITableViewCell 即将出现在屏幕上时, 会调用- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法, 所以我们在这里来判断他的点击状态

这里取出数组中对应的位置,进行重新生成被点中状态的cell状态


if (indexPath.section == 0)
    {
        // 如果是字典类, 说明这个组的在数组中的位置为字典, 说明之前有点击过这个组的按钮
        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
            {
                // 普通没有被选中状态
                cell = [self nomallCellView:indexPath andTableView:tableView andRiskModel:riskModel];
            }
            
            return cell;

        }else
        {
            // 没有点击过, 就返回没选中的cell
            // 普通没有被选中状态
             UITableViewCell * cell = [self nomallCellView:indexPath andTableView:tableView andRiskModel:riskModel];
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
            return cell;
        }

以下是示例第一个选项被点中时, 生成的cell状态

- (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;
    }

}

有个注意点就是数组的插入不要使用insertObject, 我最后使用了repalceObjectAtIndex的方式将字典存放在对应的数组位置中, 因为我发现使用insert的方式, 偶尔在来回滚动的过程中, 生成数组时有时会取不出对应的字典, 导致后面的cell重现变为没有选中状态

单选实现的文件已经放在了gitHub 上, 小家可以来这里下载问卷调查(单选)
文件暂时还没有整理, 有点乱,后期有时间我会再整理, 但是不影响使用, 打开可直接运行, 希望对小伙伴们有用

你可能感兴趣的:(单选问答题实现思路(UITableView方式))