公司有這么個(gè)需求, 要求用戶在線填寫單選形式的答題,效果如下:
這里要注意的是, 每題對(duì)應(yīng)的ABCD選項(xiàng)都有對(duì)應(yīng)的分?jǐn)?shù), 提交后計(jì)算總分?jǐn)?shù), 每題單選,共10道題, 并且在頁(yè)面滑動(dòng)回之前答過(guò)的題后, 要顯示之前已經(jīng)選擇過(guò)的選項(xiàng)
當(dāng)然其實(shí)這個(gè)簡(jiǎn)單的也面, 要實(shí)現(xiàn)并不難, UIScollView + 自定義UIView 容器就可以實(shí)現(xiàn), 公司安卓端就是這么實(shí)現(xiàn)的, 但是缺點(diǎn)也很顯著, 同一個(gè)頁(yè)面控件太多, 最終導(dǎo)致了項(xiàng)目崩潰
我個(gè)人在寫項(xiàng)目的時(shí)候, 能用UITableView 的時(shí)候盡量不會(huì)使用UIScrollView, 所以我第一選擇是使用UITableViewController, 但是使用不分組形式, 因?yàn)橐婚_(kāi)始看起來(lái)每道題目都是類似的界面, 做起來(lái)應(yīng)該會(huì)很簡(jiǎn)單, 原數(shù)據(jù)保存在risk.json中
以下是我一開(kāi)始的部分代碼
- (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ù)解析出來(lái), 后來(lái)做著做著發(fā)現(xiàn)一個(gè)問(wèn)題, 就是我使用的是不分組形式, 一道題里的選項(xiàng),全部放在一個(gè)cell中
當(dāng)你點(diǎn)擊一個(gè)cell時(shí), 在- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
方法中,沒(méi)有辦法區(qū)分你到底是選擇了哪道題, 那么你選擇的那個(gè)題目的分?jǐn)?shù)也就無(wú)法取出來(lái)
所以我又放棄了這種做法, 改為使用分組形式, 一個(gè)問(wèn)題為一個(gè)組, 一個(gè)選擇項(xiàng)為一個(gè)UITableViewCell
可是做著又發(fā)現(xiàn)一個(gè)問(wèn)題, 循環(huán)利用, cell 界面需要將你點(diǎn)擊的那道題目的按鈕變?yōu)檫x中狀態(tài), 這個(gè)狀態(tài)是要保存的, 當(dāng)你重新滾回你選擇的題目時(shí),要有之前選中的題目按鈕為選中狀態(tài), 界面不再試一個(gè)靜態(tài)的數(shù)據(jù)頁(yè)面, 你在重新滾回這個(gè)界面時(shí), 從新添加數(shù)據(jù)已經(jīng)不能滿足需求了
為了解決這個(gè)問(wèn)題
-
首先, 我在生成cell時(shí), 不使用循環(huán)生成,
screenshot.png 這樣的話,生成的cell數(shù)據(jù)正確, 但是按鈕點(diǎn)擊的狀態(tài)沒(méi)法實(shí)現(xiàn), 所以我使用了字典, 每組一個(gè)字典,分別用indexpath.section 作為key, 被選擇的index.row作為value, 然后將字典按順序保存在數(shù)組中
根據(jù)蘋果的特性, 當(dāng)上拉或者下拉UITableViewController, 一個(gè)UITableViewCell 即將出現(xiàn)在屏幕上時(shí), 會(huì)調(diào)用- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
方法, 所以我們?cè)谶@里來(lái)判斷他的點(diǎn)擊狀態(tài)
這里取出數(shù)組中對(duì)應(yīng)的位置,進(jìn)行重新生成被點(diǎn)中狀態(tài)的cell狀態(tài)
if (indexPath.section == 0)
{
// 如果是字典類, 說(shuō)明這個(gè)組的在數(shù)組中的位置為字典, 說(shuō)明之前有點(diǎn)擊過(guò)這個(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
{
// 普通沒(méi)有被選中狀態(tài)
cell = [self nomallCellView:indexPath andTableView:tableView andRiskModel:riskModel];
}
return cell;
}else
{
// 沒(méi)有點(diǎn)擊過(guò), 就返回沒(méi)選中的cell
// 普通沒(méi)有被選中狀態(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的方式, 偶爾在來(lái)回滾動(dòng)的過(guò)程中, 生成數(shù)組時(shí)有時(shí)會(huì)取不出對(duì)應(yīng)的字典, 導(dǎo)致后面的cell重現(xiàn)變?yōu)闆](méi)有選中狀態(tài)
單選實(shí)現(xiàn)的文件已經(jīng)放在了gitHub 上, 小家可以來(lái)這里下載問(wèn)卷調(diào)查(單選)
文件暫時(shí)還沒(méi)有整理, 有點(diǎn)亂,后期有時(shí)間我會(huì)再整理, 但是不影響使用, 打開(kāi)可直接運(yùn)行, 希望對(duì)小伙伴們有用