單選問答題實(shí)現(xiàn)思路(UITableView方式)

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

風(fēng)險(xiǎn)評(píng)估頁面

這里要注意的是, 每題對(duì)應(yīng)的ABCD選項(xiàng)都有對(duì)應(yīng)的分?jǐn)?shù), 提交后計(jì)算總分?jǐn)?shù), 每題單選,共10道題, 并且在頁面滑動(dòng)回之前答過的題后, 要顯示之前已經(jīng)選擇過的選項(xiàng)

當(dāng)然其實(shí)這個(gè)簡單的也面, 要實(shí)現(xiàn)并不難, UIScollView + 自定義UIView 容器就可以實(shí)現(xiàn), 公司安卓端就是這么實(shí)現(xiàn)的, 但是缺點(diǎn)也很顯著, 同一個(gè)頁面控件太多, 最終導(dǎo)致了項(xiàng)目崩潰

我個(gè)人在寫項(xiàng)目的時(shí)候, 能用UITableView 的時(shí)候盡量不會(huì)使用UIScrollView, 所以我第一選擇是使用UITableViewController, 但是使用不分組形式, 因?yàn)橐婚_始看起來每道題目都是類似的界面, 做起來應(yīng)該會(huì)很簡單, 原數(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)一個(gè)問題, 就是我使用的是不分組形式, 一道題里的選項(xiàng),全部放在一個(gè)cell中


screenshot.png

當(dāng)你點(diǎn)擊一個(gè)cell時(shí), 在- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 方法中,沒有辦法區(qū)分你到底是選擇了哪道題, 那么你選擇的那個(gè)題目的分?jǐn)?shù)也就無法取出來

所以我又放棄了這種做法, 改為使用分組形式, 一個(gè)問題為一個(gè)組, 一個(gè)選擇項(xiàng)為一個(gè)UITableViewCell
可是做著又發(fā)現(xiàn)一個(gè)問題, 循環(huán)利用, cell 界面需要將你點(diǎn)擊的那道題目的按鈕變?yōu)檫x中狀態(tài), 這個(gè)狀態(tài)是要保存的, 當(dāng)你重新滾回你選擇的題目時(shí),要有之前選中的題目按鈕為選中狀態(tài), 界面不再試一個(gè)靜態(tài)的數(shù)據(jù)頁面, 你在重新滾回這個(gè)界面時(shí), 從新添加數(shù)據(jù)已經(jīng)不能滿足需求了

為了解決這個(gè)問題

  1. 首先, 我在生成cell時(shí), 不使用循環(huán)生成,


    screenshot.png
  2. 這樣的話,生成的cell數(shù)據(jù)正確, 但是按鈕點(diǎn)擊的狀態(tài)沒法實(shí)現(xiàn), 所以我使用了字典, 每組一個(gè)字典,分別用indexpath.section 作為key, 被選擇的index.row作為value, 然后將字典按順序保存在數(shù)組中

Snip20170327_2.png

Snip20170327_1.png

根據(jù)蘋果的特性, 當(dāng)上拉或者下拉UITableViewController, 一個(gè)UITableViewCell 即將出現(xiàn)在屏幕上時(shí), 會(huì)調(diào)用- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法, 所以我們在這里來判斷他的點(diǎn)擊狀態(tài)

這里取出數(shù)組中對(duì)應(yīng)的位置,進(jìn)行重新生成被點(diǎn)中狀態(tài)的cell狀態(tài)


if (indexPath.section == 0)
    {
        // 如果是字典類, 說明這個(gè)組的在數(shù)組中的位置為字典, 說明之前有點(diǎn)擊過這個(gè)組的按鈕
        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;
        }

以下是示例第一個(gè)選項(xiàng)被點(diǎn)中時(shí), 生成的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;
    }

}

有個(gè)注意點(diǎn)就是數(shù)組的插入不要使用insertObject, 我最后使用了repalceObjectAtIndex的方式將字典存放在對(duì)應(yīng)的數(shù)組位置中, 因?yàn)槲野l(fā)現(xiàn)使用insert的方式, 偶爾在來回滾動(dòng)的過程中, 生成數(shù)組時(shí)有時(shí)會(huì)取不出對(duì)應(yīng)的字典, 導(dǎo)致后面的cell重現(xiàn)變?yōu)闆]有選中狀態(tài)

單選實(shí)現(xiàn)的文件已經(jīng)放在了gitHub 上, 小家可以來這里下載問卷調(diào)查(單選)
文件暫時(shí)還沒有整理, 有點(diǎn)亂,后期有時(shí)間我會(huì)再整理, 但是不影響使用, 打開可直接運(yùn)行, 希望對(duì)小伙伴們有用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容