iOS 答题功能实现 —— HERO博客

上一篇简述了搭建项目框架的流程,本篇在此基础上实用,做了一个简单的类似题库答题页面。

首先看一下效果图:

 

简单阐述一下:这里没有做网络请求数据,题目数据是本地模拟服务端写的,没有做本地缓存,每次进入、上一题、下一题时去获取服务端数据,如果有选择选项或填写答案时,在上一题、下一题及退出时保存做题记录。答题页面控制器HWQuestionsVC继承基类HWBaseViewController,在HWQuestionsVC的view上添加了几个自定义视图,根据题目类型及内容布局刷新界面。下面贴上控制器HWQuestionsVC的代码,完整demo可在下面链接下载。

 

#import "HWQuestionsVC.h"
#import "HWQuestionsModel.h"
#import "HWQuestionsFooterView.h"
#import "HWAnswerView.h"
#import "HWFillAnswerView.h"
#import "HWAnalysisView.h"

@interface HWQuestionsVC ()<HWAnalysisViewDelegate, HWQuestionsFooterViewDelegate>

@property (nonatomic, strong) NSMutableArray *questionsArray;
@property (nonatomic, strong) HWQuestionsModel *model;
@property (nonatomic, weak) UIScrollView *scrollView;
@property (nonatomic, weak) UILabel *questionlabel;
@property (nonatomic, weak) HWQuestionsFooterView *footerView;
@property (nonatomic, weak) HWAnswerView *answerView;
@property (nonatomic, weak) HWFillAnswerView *fillAnswerView;
@property (nonatomic, weak) HWAnalysisView *analysisView;
@property (nonatomic, assign) NSInteger page;
@property (nonatomic, assign) BOOL isCreatControl;

@end

@implementation HWQuestionsVC

- (NSMutableArray *)questionsArray
{
    if (!_questionsArray) {
        _questionsArray = [NSMutableArray array];
    }
    
    return _questionsArray;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    //设置导航栏标题并添加返回按钮
    [self addBackBtnAndTitle:@"答题页面"];
    
    //初始化页码
    _page = 1;
    
    //模拟题目数据(服务端数据库)
    [self setQuestionsArray];
    
    //获取题目信息,每次获取当前目标题目信息
    [self getQuestionsInfo];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    //保存做题记录
    [self saveProgress];
}

//模拟题目数据(服务端数据库)
- (void)setQuestionsArray
{
    NSArray *array = @[
                        @{@"questionid" : @"1000", @"totalCount" : @"5", @"question" : @"如果昨天是明天的话就好了,这样今天就周五了。真实的今天可能是星期几?", @"questiontype" : @"1", @"questiontype_text" : @"单选题", @"questionselectnumber" : @"3", @"questiondescribe" : @"星期三:理想今天是星期五,昨天是星期四,真实明天是理想的昨天是星期四,真实的今天是星期三。\n星期日:理想今天是星期五,明天是星期六,真实昨天是理想的明天是星期六,真实的今天是星期日。", @"trueanswer" : @"A", @"userAnswer" : @[], @"tkselect" : @[@"A:星期三", @"B:星期四", @"C:星期五"]},
                        @{@"questionid" : @"1001", @"totalCount" : @"5", @"question" : @"这里是问题,这道题的答案是AC。这里是问题,这道题的答案是AC。这里是问题,这道题的答案是AC。", @"questiontype" : @"2", @"questiontype_text" : @"多选题", @"questionselectnumber" : @"5", @"questiondescribe" : @"这里是答案解析,这里可以很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的。", @"trueanswer" : @"AC", @"userAnswer" : @[], @"tkselect" : @[@"A:这个选项是正确的。这个选项是正确的。这个选项是正确的。", @"B:这个选项是错误的。这个选项是错误的。这个选项是错误的。", @"C:这个选项是正确的。这个选项是正确的。这个选项是正确的。", @"D:这个选项是错误的。这个选项是错误的。这个选项是错误的。", @"E:这个选项是错误的。这个选项是错误的。这个选项是错误的。"]},
                        @{@"questionid" : @"1002", @"totalCount" : @"5", @"question" : @"小明被老师赶出来后决定进入IT行业,日以继夜的学习C、C++...,通过不断的努力学习,小明成功入职快递公司成为一名优秀的快递员。小明的做法是正确的么?", @"questiontype" : @"3", @"questiontype_text" : @"判断题", @"questionselectnumber" : @"4", @"questiondescribe" : @"小明读了《从入门到放弃》这本书。", @"trueanswer" : @"A", @"userAnswer" : @[], @"tkselect" : @[]},
                        @{@"questionid" : @"1003", @"totalCount" : @"5", @"question" : @"既然选择了____________,便只顾____________。", @"questiontype" : @"4", @"questiontype_text" : @"填空题", @"questionselectnumber" : @"2", @"questiondescribe" : @"参考答案:既然选择了远方,便只顾风雨兼程。", @"trueanswer" : @"", @"userAnswer" : @[], @"tkselect" : @[]},
                        @{@"questionid" : @"1004", @"totalCount" : @"5", @"question" : @"在ARC环境下这段代码为什么不会崩溃?\n@property (nonatomic, weak) void(^block)();\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    void(^ __weak blockA)() = ^{\n        NSLog(@“just a block”);\n    }\n\n    _block = blockA;\n};\n\n _block();", @"questiontype" : @"5", @"questiontype_text" : @"简答题", @"questionselectnumber" : @"1", @"questiondescribe" : @"ARC 下 block 没有捕获外部变量,block 代码被放在静态代码区,程序运行后,内存地址不变。", @"trueanswer" : @"", @"userAnswer" : @[], @"tkselect" : @[]}
                        ];
    
    self.questionsArray = [HWQuestionsModel mj_objectArrayWithKeyValuesArray:array];
}

//获取题目信息,每次获取当前目标题目信息
- (void)getQuestionsInfo
{
    //更新模型
    _model = _questionsArray[_page - 1];
    
    //创建控件
    if (!_isCreatControl) [self creatControl];
    
    //刷新视图
    [self reloadView];
}

//保存做题记录,做过的题由服务端存储,不需要进行本地持久化保存
- (void)saveProgress
{
    if (([_model.questiontype intValue] < 4 && ![_answerView.selectAnswer isEqualToString:@""]) || ([_model.questiontype intValue] > 3 && ![_fillAnswerView.fillAnswer isEqualToString:@""])) {
        
        NSString *qranswer = _answerView.hidden ? _fillAnswerView.fillAnswer : _answerView.selectAnswer;
        NSString *qrnum = _answerView.hidden ? _fillAnswerView.qrnum : _answerView.qrnum;
        HWLog(@"保存做题记录参数:\n试题id:%@\n页码:%ld\n填写的答案:%@\n填写的答案角标:%@", _model.questionid, _page, qranswer, qrnum);
        
        //提交服务端保存记录
        HWQuestionsModel *model = _questionsArray[_page - 1];
        [model.userAnswer removeAllObjects];
        model.userAnswer = [[qranswer componentsSeparatedByString:@"|"] mutableCopy];
    }
}

//创建控件
- (void)creatControl
{
    _isCreatControl = YES;
    
    //滚动视图
    UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, KMainW, KMainH - 113)];
    scrollView.showsVerticalScrollIndicator = NO;
    [self.view addSubview:scrollView];
    self.scrollView = scrollView;
    
    //问题标签
    UILabel *questionLabel = [[UILabel alloc] init];
    questionLabel.textColor = [UIColor colorWithHexString:@"#292929"];
    questionLabel.font = [UIFont systemFontOfSize:15.f];
    questionLabel.numberOfLines = 0;
    [scrollView addSubview:questionLabel];
    self.questionlabel = questionLabel;
    
    //答案选择视图,单选、多选、判断
    HWAnswerView *answerView = [[HWAnswerView alloc] init];
    [scrollView addSubview:answerView];
    self.answerView = answerView;
    
    //答案填写视图,填空、简答
    HWFillAnswerView *fillAnswerView = [[HWFillAnswerView alloc] init];
    [scrollView addSubview:fillAnswerView];
    self.fillAnswerView = fillAnswerView;
    
    //解析视图
    HWAnalysisView *analysisView = [[HWAnalysisView alloc] init];
    analysisView.delegate = self;
    [scrollView addSubview:analysisView];
    self.analysisView = analysisView;
    
    //底部视图
    HWQuestionsFooterView *footerView = [[HWQuestionsFooterView alloc] initWithFrame:CGRectMake(0, KMainH - 49 - 64, KMainW, 49)];
    footerView.delegate = self;
    [self.view addSubview:footerView];
    self.footerView = footerView;
    [self reloadFooterViewState];
}

//刷新布局
- (void)reloadView
{
    //刷新问题相关数据
    NSString *questionlabelText = [NSString stringWithFormat:@"(%@)%ld. %@", _model.questiontype_text, _page, _model.question];
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    [paragraphStyle setLineSpacing:4.0f];
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:questionlabelText];
    NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:kMainColor, NSForegroundColorAttributeName, nil];
    [attributedString setAttributes:attrs range:NSMakeRange(0, 5)];
    [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [questionlabelText length])];
    NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:15.f], NSParagraphStyleAttributeName:paragraphStyle};
    CGFloat questionLabelH = [questionlabelText boundingRectWithSize:CGSizeMake(KMainW - 20, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:dic context:nil].size.height;
    _questionlabel.attributedText = attributedString;
    _questionlabel.frame = CGRectMake(10, 10, KMainW - 20, questionLabelH);
    
    //刷新答案相关数据
    if ([_model.questiontype intValue] < 4) {
        //答案选择视图,单选、多选、判断
        _answerView.hidden = NO;
        _fillAnswerView.hidden = YES;
        [_answerView reloadViewWithFrame:CGRectMake(0, CGRectGetMaxY(_questionlabel.frame) + 15, KMainW, 0) style:[_model.questiontype intValue] - 1 answerArray:_model.tkselect userAnswers:_model.userAnswer];
        
    }else {
        //答案填写视图,填空、简答
        _answerView.hidden = YES;
        _fillAnswerView.hidden = NO;
        [_fillAnswerView reloadViewWithFrame:CGRectMake(0, CGRectGetMaxY(_questionlabel.frame) + 15, KMainW, 0) style:[_model.questiontype intValue] - 4 answerCount:_model.questionselectnumber userAnswers:_model.userAnswer];
    }
    
    //刷新解析相关数据
    CGFloat analysisViewY = _answerView.hidden ? CGRectGetMaxY(_fillAnswerView.frame) + 10 : CGRectGetMaxY(_answerView.frame) + 20;
    _analysisView.frame = CGRectMake(0, analysisViewY, KMainW, 44);
    _analysisView.trueAnswer = _model.trueanswer;
    _analysisView.analysisInfo = _model.questiondescribe;
    [_analysisView dismissAnalysisInfo];
    
    //设置滚动区域内容
    _scrollView.contentSize = CGSizeMake(KMainW, analysisViewY + 44);
}

#pragma mark - SXQuestionsFooterViewDelegate
- (void)questionsFooterView:(HWQuestionsFooterView *)questionsFooterView didClickOptionButton:(BOOL)isNextButton
{
    //保存做题记录
    [self saveProgress];
    
    //更新页码
    isNextButton ? _page++ : _page--;
    
    //获取目标题目信息
    [self getQuestionsInfo];
    
    //刷新底部视图状态
    [self reloadFooterViewState];
}

//刷新底部视图状态
- (void)reloadFooterViewState
{
    UIButton *btn = (UIButton *)[self.footerView viewWithTag:500];
    btn.enabled = _page == 1 ? NO : YES;
    UIButton *otButton = (UIButton *)[self.footerView viewWithTag:501];
    otButton.enabled = _page == [_model.totalCount integerValue] ? NO : YES;
}

#pragma mark - SXAnalysisViewDelegate
- (void)didClickAnaBtnInAnalysisView:(HWAnalysisView *)analysisView
{
    [analysisView reloadViewWithUserResult:_answerView.selectAnswer showTFView:[_model.questiontype intValue] < 4];
    
    CGFloat temH = _answerView.hidden ? CGRectGetMaxY(_fillAnswerView.frame) + 10 : CGRectGetMaxY(_answerView.frame) + 20;
    
    _scrollView.contentSize = CGSizeMake(KMainW, temH + 10 + analysisView.bounds.size.height);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

@end

 

 

Demo 下载链接:http://code.cocoachina.com/view/135213

写博客的初心是希望大家共同交流成长,博主水平有限难免有偏颇之处,欢迎批评指正。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 34
    评论
实现iOS的聊天输入框功能,可以按照以下步骤进行: 第一步,创建一个包含输入框的视图控制器。可以使用UITextField或UITextView来创建输入框,并设置好相应的属性,例如输入框的大小、位置、边框样式等。 第二步,设置输入框的代理。通过设置输入框的代理,可以监听输入框的文字变化、键盘弹出和隐藏等事件,并做出相应的处理。 第三步,实现输入框的自动调整高度功能。聊天输入框通常需要根据输入的文字内容自动调整高度,以方便用户输入长文本。可以通过监听输入框的文字变化,并计算输入框内容所需的高度,然后实时更新输入框的高度。 第四步,处理键盘的弹出和隐藏。当用户点击输入框时,系统会自动弹出键盘。为了不遮挡输入框,需要将输入框随键盘的弹出而上移,以保证用户能够看到正在输入的文字。可以使用NSNotification来监听键盘的弹出和隐藏事件,并相应地更新输入框的位置。 第五步,实现发送按钮的功能。在聊天输入框中一般会有一个发送按钮,用于发送消息。可以通过添加一个UIButton,并设置好按钮的样式和位置。然后,监听发送按钮的点击事件,并处理发送消息的逻辑,例如将消息发送到服务器或本地数据库。 在实现聊天输入框功能的过程中,还可以根据需求添加一些其他的功能,如表情符号的支持、附件的发送等。通过以上步骤,就可以实现一个基本的聊天输入框功能

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值