iOS开发 • 实例——用CollectionView和tabl

作者: 行走的苹果哥 | 来源:发表于2017-10-07 10:52 被阅读1154次

    上个月,我独立开发的 融易点 已成功上架了,是一款为高校学生金融知识学习做服务的app,目前是1.0版本。那里面逻辑比较复杂的界面,就是做题界面,有单选、多选题、判断题、简答题等等,类似的demo,很少,我也参考了一些,学到了不少经验,值得写下来分享,这个项目第一版功能相对简单,所以我还是采用了MVC的架构,我们先看看效果,如下所示:

    1.gif

    简单说说实现的界面层次结构:
    ViewController中,主要的有:self.view->UICollectionView->UITableView
    当然了,界面上还有UIImageView、UIProgressView、UIButton,这些是次要的。
    接下来,开始具体的实现过程,首先,自定义选项的cell,我使用的是xib,同时创建HomePowerExamModel,如图所示:

    image.png image.png image.png

    创建3个tableView,我把他们命名为:HomeBaseExamTV,HomeSingleTV,HomeMultiTV,让后面两个继承于第一个,先看看HomeBaseExamTV的代码:

    #import <UIKit/UIKit.h>
    @class HomePowerExamModel;
    @interface HomeBaseExamTV : UITableView<UITableViewDataSource,UITableViewDelegate>
    @property (nonatomic, strong) HomePowerExamModel * ExModel;
    @property(nonatomic,strong) NSArray *answerList;
    @property(nonatomic,strong) NSArray *questionList;
    // 答案字典
    @property(nonatomic,copy) NSDictionary *answer;
    //  默认选中的答案
    @property (nonatomic,copy) NSString *tempAnswer;
    
    /**
     通用设置  子类实现必须调用super
     @param model      数据模型
     @param index      第几题
     */
    - (void)config:(HomePowerExamModel *)model index:(NSInteger)index;
    @end
    
    #import "HomeBaseExamTV.h"
    #import "HomePowerExamModel.h"
    
    @interface HomeBaseExamTV()
    
    @end
    
    @implementation HomeBaseExamTV
    - (NSArray *)answerList{
        if (!_answerList) {
            _answerList = @[@"A",@"B",@"C",@"D",@"E"];
        }
        return _answerList;
    }
    
    - (NSArray *)questionList{
        if (!_questionList) {
            _questionList =  @[NONullString(_ExModel.QB_A),NONullString(_ExModel.QB_B),NONullString(_ExModel.QB_C),NONullString(_ExModel.QB_D),NONullString(_ExModel.QB_E)];
        }
        return _questionList;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            self.separatorStyle = UITableViewCellSeparatorStyleNone;
        }
        return self;
    }
    
    - (void)config:(HomePowerExamModel *)model index:(NSInteger)index
    {
        self.ExModel = model;
        UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.width, 0)];
        UILabel * titleLb;
        /*题目文字*/
        if (iphoneSE) {
            titleLb = [[UILabel alloc] initWithFrame:CGRectMake(10, 20, self.width-15, 0)];
        } else if (iphone7)
        {
            titleLb = [[UILabel alloc] initWithFrame:CGRectMake(10, 25, self.width-15, 0)];
        } else
        {
            titleLb = [[UILabel alloc] initWithFrame:CGRectMake(10, 35, self.width-20, 0)];
        }
        
        titleLb.numberOfLines = 0;
        titleLb.text = [NSString stringWithFormat:@"%zd、%@",index+1,model.QB_Description];
        if (iphoneSE) {
            titleLb.font = [UIFont systemFontOfSize:14];
        } else
        {
            titleLb.font = [UIFont systemFontOfSize:15];
        }
        [titleLb sizeToFit];
        titleLb.textColor = [UIColor colorWithHexColorString:@"#3c4a55" alpha:1.0];
        titleLb.textAlignment = NSTextAlignmentNatural;
        [headerView addSubview:titleLb];
        headerView.height = titleLb.bottom + 10;
        self.tableHeaderView = headerView;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return 0;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return nil;
    }
    

    接下来看看HomeSingleTV的代码,由于判断题也属于单选题,不一样的是,单选题最多有5个选项,判断题只有两个选项,后台有返回一个type判断题型,所以共用一个tableView,如下代码所示:

    #import "HomeBaseExamTV.h"
    
    @interface HomeSingleTV : HomeBaseExamTV
    
    @end
    
    #import "HomeSingleTV.h"
    #import "HomeSelectionCell.h"
    #import "HomePowerExamModel.h"
    
    @interface HomeSingleTV()<UITableViewDelegate,UITableViewDataSource>
    @property (nonatomic, strong) HomePowerExamModel  *model;
    @property (nonatomic,strong) NSMutableDictionary  *rowHeightDic;
    @property(nonatomic,assign) NSInteger selected;
    @end
    
    @implementation HomeSingleTV
    
    - (NSMutableDictionary *)rowHeightDic
    {
        if (!_rowHeightDic) {
            _rowHeightDic = [NSMutableDictionary dictionary];
        }
        return _rowHeightDic;
    }
    
    - (NSDictionary *)answer{
        
        if (self.selected != -1)
        {
            return  @{@"QuestionBID":@([self.model.QuestionBId intValue]),@"answer":self.answerList[_selected]};
        } else
        {
             return @{@"QuestionBID":@([self.model.QuestionBId intValue]),@"answer":@""};
        }
    }
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            self.selected = -1;
            [self registerNib:[UINib nibWithNibName:@"HomeSelectionCell" bundle:nil] forCellReuseIdentifier:@"HomeSelectionCell"];
            self.backgroundColor = [UIColor clearColor];
            self.bounces = NO;
        }
        return self;
    }
    
    - (void)config:(HomePowerExamModel *)model index:(NSInteger)index{
        [super config:model index:index];//调用父类方法  设置通用设置
        self.model = model;
        self.delegate = self;
        self.dataSource = self;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        if ([self.model.QB_Type isEqualToString:@"3"]) {
            return 2;
        }
        else
        {
            return self.questionList.count;
        }
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        HomeSelectionCell * cell = [tableView dequeueReusableCellWithIdentifier:@"HomeSelectionCell"];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        cell.contentLb.text = [NSString stringWithFormat:@"%@",self.questionList[indexPath.row]];
        cell.contentLb.textColor = [UIColor colorWithHexColorString:@"#666666" alpha:1.0];
        cell.contentLb.font = [UIFont systemFontOfSize:14];
        cell.backgroundColor = [UIColor clearColor];
        NSArray * normalImgName = @[@"A1",@"B1",@"C1",@"D1",@"E1"];
        NSArray * selectImgName = @[@"A2",@"B2",@"C2",@"D2",@"E2"];
        [cell.selectBtn setImage:ImageNamed(normalImgName[indexPath.row]) forState:UIControlStateNormal];
        [cell.selectBtn setImage:ImageNamed(selectImgName[indexPath.row]) forState:UIControlStateSelected];
        if ([cell.contentLb.text isEqualToString:@""]) {
            cell.selectBtn.hidden = YES;
        } else
        {
            cell.selectBtn.hidden = NO;
        }
        
        cell.backgroundColor = [UIColor clearColor];
        if (indexPath.row == self.selected)
        {
            cell.selectBtn.selected = YES;
            
        } else
        {
            cell.selectBtn.selected = NO;
        }
        cell.selectBtn.tag = indexPath.row;
        [cell.selectBtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        
        CGFloat height = [self getHeightWithStr:cell.contentLb.text];
        if (iphoneSE)
        {
            cell.bgView.frame = CGRectMake(0, 0, 270, height);
            cell.selectBtn.frame = CGRectMake(10, 2, 55, height);
            cell.contentLb.frame = CGRectMake(50, 2, 225, height);
        }
        else if (iphone7)
        {
            cell.bgView.frame = CGRectMake(0, 0, 275, height);
            cell.selectBtn.frame = CGRectMake(10, 2, 55, height);
            cell.contentLb.frame = CGRectMake(50, 2, 225, height);
        }
        else
        {
            cell.bgView.frame = CGRectMake(0, 0, 275, height);
            cell.selectBtn.frame = CGRectMake(15, 2, 55, height);
            cell.contentLb.frame = CGRectMake(50, 2, 225, height);
        }
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        self.selected = indexPath.row;
        [self reloadData];
    }
    
    /*根据返回的选项文字长度动态计算cell高度*/
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSNumber *number = [self.rowHeightDic objectForKey:@(indexPath.row).description];
        if (number) {
            if (iphoneSE) {
                return number.floatValue;
            }
            else
            {
                return number.floatValue + 10;
            }
        }else{
            CGFloat height = [self getHeightWithStr:self.questionList[indexPath.row]];
            [self.rowHeightDic setValue:[NSNumber numberWithFloat:height] forKey:@(indexPath.row).description];
            return height;
        }
    }
    
    - (CGFloat)getHeightWithStr:(NSString *)str{
        return  [self calculateStringHeight:str width:SCREEN_WIDTH - 10 -18 -5 -10 fontSize:17] + 15;
    }
    
    //  计算文字高度
    - (CGFloat)calculateStringHeight:(NSString *)str width:(CGFloat)width fontSize:(CGFloat)size{
        
        return  [str boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:size]} context:nil].size.height;
        
    }
    
    /*保存已答过的答案*/
    - (void)setTempAnswer:(NSString *)tempAnswer{
        if (tempAnswer.length == 0)
            return;
        _selected = [self.answerList indexOfObject:tempAnswer];
        [self reloadData];
    }
    
    /*单选点击选项*/
    - (void)selectBtnClick:(UIButton *)btn
    {
        self.selected = btn.tag;
        [self reloadData];
    }
    @end
    

    接着是HomeMultiTV的代码,多选题由于有多种组合,所以需要做两种处理:一、对多选题答案进行快速排序,我是用数组来保存答案,所以对数组进行快速排序;
    二、多选题在没有提交答案的时候,选项是可以重新选,通过按钮来实现。

    完整代码如下:

    #import "HomeBaseExamTV.h"
    
    @interface HomeMultiTV : HomeBaseExamTV
    
    @end
    
    #import "HomeMultiTV.h"
    #import "HomeSelectionCell.h"
    #import "HomePowerExamModel.h"
    
    @interface HomeMultiTV ()<UITableViewDelegate,UITableViewDataSource>
    
    @property (nonatomic,strong) NSMutableDictionary *rowHeightDic;
    @property(nonatomic,strong) NSMutableArray *selectedArray;
    @property (nonatomic, strong) NSArray * multiAnswerList;
    
    @end
    
    @implementation HomeMultiTV
    - (NSMutableDictionary *)rowHeightDic{
        if (!_rowHeightDic) {
            _rowHeightDic = [NSMutableDictionary dictionary];
        }
        return _rowHeightDic;
    }
    
    - (NSArray *)multiAnswerList
    {
        if (!_multiAnswerList) {
            _multiAnswerList = @[@"A,",@"B,",@"C,",@"D,",@"E,"];
        }
        return _multiAnswerList;
    }
    
    /*后台对多选题的答案要求按照ABCDE这样的顺序,所以进行排序*/
    - (NSDictionary *)answer{
        
        NSString *answer = @"";
        NSString *Answer = @"";
        /*给数组快速排序*/
        [self.selectedArray sortUsingSelector:@selector(compare:)];
        for (NSNumber *number in self.selectedArray) {
            Answer =  [Answer stringByAppendingString:self.multiAnswerList[number.intValue]];
        }
        if (Answer.length > 0) {
            answer = [Answer substringToIndex:[Answer length]-1];
        }
        
        if (answer.length>0)
        {
            return @{@"QuestionBID":@([self.ExModel.QuestionBId intValue]),@"answer":answer};
        } else
        {
            return @{@"QuestionBID":@([self.ExModel.QuestionBId intValue]),@"answer":@""};
        }
    }
    
    - (NSMutableArray *)selectedArray{
        if (!_selectedArray) {
            _selectedArray = [NSMutableArray array];
            
        }
        return _selectedArray;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            
            [self registerNib:[UINib nibWithNibName:@"HomeSelectionCell" bundle:nil] forCellReuseIdentifier:@"HomeSelectionCell"];
            self.backgroundColor = [UIColor clearColor];
            self.bounces = NO;
        }
        return self;
    }
    
    - (void)config:(HomePowerExamModel *)model index:(int)index
    {
        [super config:model index:index];
        self.delegate = self;
        self.dataSource = self;
    }
    
    /*保存答案*/
    - (void)setTempAnswer:(NSString *)tempAnswer{
        
        if (tempAnswer.length == 0)
            return;
        for(int i =0; i < [tempAnswer length]; i++)
        {
            NSString *str = [tempAnswer substringWithRange:NSMakeRange(i, 1)];
            if (![str isEqualToString:@","]) {
                NSInteger index =  [self.answerList indexOfObject:str];
                if (![self.selectedArray containsObject:@(index)])
                {
                    [self.selectedArray addObject:@(index)];
                }
            }
        }
        
        [self reloadData];
    }
    
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.questionList.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        HomeSelectionCell * cell = [tableView dequeueReusableCellWithIdentifier:@"HomeSelectionCell"];
        cell.contentLb.text = [NSString stringWithFormat:@"%@",self.questionList[indexPath.row]];
        cell.contentLb.font = [UIFont systemFontOfSize:14];
        cell.contentLb.textColor = [UIColor colorWithHexColorString:@"#666666" alpha:1.0];
        NSArray * normalImgName = @[@"A1",@"B1",@"C1",@"D1",@"E1"];
        NSArray * selectImgName = @[@"A2",@"B2",@"C2",@"D2",@"E2"];
        [cell.selectBtn setImage:ImageNamed(normalImgName[indexPath.row]) forState:UIControlStateNormal];
        [cell.selectBtn setImage:ImageNamed(selectImgName[indexPath.row]) forState:UIControlStateSelected];
        
        if ([cell.contentLb.text isEqualToString:@""]) {
            cell.selectBtn.hidden = YES;
        }
        else
        {
            cell.selectBtn.hidden = NO;
        }
        
        if ([self.selectedArray containsObject:@(indexPath.row)])
        {
            cell.selectBtn.selected = YES;
        } else
        {
            cell.selectBtn.selected = NO;
        }
        cell.backgroundColor = [UIColor clearColor];
        cell.selectBtn.tag = indexPath.row;
        [cell.selectBtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        
        CGFloat height = [self _getHeightWithStr:cell.contentLb.text];
        if (iphoneSE)
        {
            cell.bgView.frame = CGRectMake(0, 0, 270, height);
            cell.selectBtn.frame = CGRectMake(10, 2, 55, height);
            cell.contentLb.frame = CGRectMake(50, 2, 225, height);
        }
        else if (iphone7)
        {
            cell.bgView.frame = CGRectMake(0, 0, 275, height);
            cell.selectBtn.frame = CGRectMake(10, 2, 55, height);
            cell.contentLb.frame = CGRectMake(50, 2, 225, height);
        }
        else
        {
            
            cell.bgView.frame = CGRectMake(0, 0, 275, height);
            cell.selectBtn.frame = CGRectMake(15, 2, 55, height);
            cell.contentLb.frame = CGRectMake(50, 2, 225, height);
        }
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if ([self.selectedArray containsObject:@(indexPath.row)]) {
            [self.selectedArray removeObject:@(indexPath.row)];
        }else{
            [self.selectedArray addObject:@(indexPath.row)];
        }
        
        [self reloadData];
    }
    
    /*动态计算高度*/
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        NSNumber *number = [self.rowHeightDic objectForKey:@(indexPath.row).description];
        
        if (number)
        {
            if (iphoneSE) {
                return number.floatValue;
            }
            else
            {
                return number.floatValue + 10;
            }
        }else{
            CGFloat height = [self _getHeightWithStr:self.questionList[indexPath.row]];
            [self.rowHeightDic setValue:
            [NSNumber numberWithFloat:height] forKey:@(indexPath.row).description];
            return height;
        }
    }
    
    - (CGFloat)_getHeightWithStr:(NSString *)str{
        return  [self calculateStringHeight:str width:SCREEN_WIDTH - 10 -18 -5 -10 fontSize:17] + 15;
    }
    
    //  计算文字高度
    - (CGFloat)calculateStringHeight:(NSString *)str width:(CGFloat)width fontSize:(CGFloat)size{
        
        return  [str boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:
    NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading 
    attributes:
    @{NSFontAttributeName:[UIFont systemFontOfSize:size]} context:nil].size.height;
    }
    
    - (void)selectBtnClick:(UIButton *)btn
    {
        if ([self.selectedArray containsObject:@(btn.tag)]) {
            [self.selectedArray removeObject:@(btn.tag)];
        }
        else
        {
            [self.selectedArray addObject:@(btn.tag)];
        }
        [self reloadData];
    }
    

    model和 View的代码已经实现,最后,看看Controller中的主要代码实现,首先,创建CollectionView:

    - (void)setupCollectionView
    {
        UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init];
        flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
        flowLayout.minimumInteritemSpacing = 0;
        flowLayout.minimumLineSpacing = 0;
        if (iphoneSE) {
            flowLayout.itemSize = CGSizeMake(260, SCREEN_HEIGHT-64);
        }
        else if (iphone7)
        {
            flowLayout.itemSize = CGSizeMake(306, SCREEN_HEIGHT-64);
        } else
        {
            flowLayout.itemSize = CGSizeMake(337, SCREEN_HEIGHT-64);
        }
        
        //确定水平滑动方向
        [flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
        if (iphoneSE) {
            self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 64, 260, SCREEN_HEIGHT-150) collectionViewLayout:flowLayout];
            self.collectionView.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
        } else if (iphone7)
        {
            self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 64, 306, SCREEN_HEIGHT-180) collectionViewLayout:flowLayout];
            self.collectionView.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
        } else
        {
            self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 64, 337, SCREEN_HEIGHT-200) collectionViewLayout:flowLayout];
            self.collectionView.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
        }
        self.collectionView.delegate = self;
        self.collectionView.dataSource = self;
        self.collectionView.pagingEnabled = YES;
        self.collectionView.scrollEnabled = NO;
        self.collectionView.showsHorizontalScrollIndicator = NO;
        self.collectionView.showsVerticalScrollIndicator = NO;
        [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"UICollectionViewCell"];
        self.collectionView.backgroundColor = [UIColor clearColor];
        [self.view addSubview:self.collectionView];
        // 首次调用
        self.collectionView.contentOffset = CGPointMake(self.currentIndex*SCREEN_WIDTH, 0);
    }
    

    紧接着,实现CollectionView的代理方法和数据源方法:

    #pragma mark -- UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
    {
        return self.dataSource.count;
    }
    
    - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"UICollectionViewCell" forIndexPath:indexPath];
        [cell.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        self.ExamModel = self.dataSource[indexPath.row];
        HomeBaseExamTV * baseTv = nil;
        //题型 1单选 2多选 3判断
        if ([self.ExamModel.QB_Type isEqualToString:@"1"])
        {
            baseTv = [[HomeSingleTV alloc] initWithFrame:CGRectZero];
            self.topicTypeLb.text = @"单选题";
        }
        else if ([self.ExamModel.QB_Type isEqualToString:@"2"])
        {
            baseTv = [[HomeMultiTV alloc] initWithFrame:CGRectZero];
            self.topicTypeLb.text = @"多选题";
        }
        else if ([self.ExamModel.QB_Type isEqualToString:@"3"])
        {
            baseTv = [[HomeSingleTV alloc] initWithFrame:CGRectZero];
            self.topicTypeLb.text = @"判断题";
        }
        
        if (iphoneSE) {
            baseTv.frame = CGRectMake(0, 140, 250, self.collectionView.height-64);
        } else if (iphone7)
        {
            baseTv.frame = CGRectMake(0, 170, 306, self.collectionView.height-64);
        } else
        {
            baseTv.frame = CGRectMake(0, 170, 337, self.collectionView.height-64);
        }
        [cell.contentView addSubview:baseTv];
        
        /*1表示做过了,看题目*/
        if(self.doneType == 1)
        {
            [baseTv config:self.ExamModel index:indexPath.item];
            baseTv.tempAnswer = self.ExamModel.userAnswer;
        } else
        {
            [baseTv config:self.ExamModel index:indexPath.item];
            baseTv.tempAnswer = self.ExamModel.userAnswer;
        }
        return cell;
    }
    

    由于做题界面是可以返回上一道题的,所以需要保存当前题目的答案,用到的方法如下:

    //单选题
    /*保存已答过的答案*/
    - (void)setTempAnswer:(NSString *)tempAnswer{
        if (tempAnswer.length == 0)
            return;
        _selected = [self.answerList indexOfObject:tempAnswer];
        [self reloadData];
    }
    
    //多选题
    /*保存答案*/
    - (void)setTempAnswer:(NSString *)tempAnswer{
        
        if (tempAnswer.length == 0)
            return;
        for(int i =0; i < [tempAnswer length]; i++)
        {
            NSString *str = [tempAnswer substringWithRange:NSMakeRange(i, 1)];
            if (![str isEqualToString:@","]) {
                NSInteger index =  [self.answerList indexOfObject:str];
                if (![self.selectedArray containsObject:@(index)])
                {
                    [self.selectedArray addObject:@(index)];
                }
            }
        }
        [self reloadData];
    }
    

    到这里,做题界面就完成了,剩下的就是一些逻辑细节功能的处理,有几个功能实现,我也写下来分享,都是最简单直接的方式,可以直接用。
    第一、时分秒计时。

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        [self regularTime];
    }
    
    - (void)regularTime
    {
        __weak typeof(self)weakSelf = self;
        /*计时秒数*/
        secondValue = 0;
        timer = [NSTimer timerWithTimeInterval:1.0f block:^{
            [weakSelf timerAction];
        } repeats:YES];
        //计算时分秒
        NSString *str_hour = [NSString stringWithFormat:@"%02d",secondValue/3600];//时
        NSString *str_minute = [NSString stringWithFormat:@"%02d",(secondValue%3600)/60];//分
        NSString *str_second = [NSString stringWithFormat:@"%02d",secondValue%60];//秒
        NSString *format_time = [NSString stringWithFormat:@"%@:%@:%@",str_hour,str_minute,str_second];
        NSLog(@"time:%@",format_time);
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    }
    
    - (void)timerAction
    {
        /*正计时*/
        secondValue++;
        NSString *str_hour = [NSString stringWithFormat:@"%02d",secondValue/3600];
        NSString *str_minute = [NSString stringWithFormat:@"%02d",(secondValue%3600)/60];
        NSString *str_second = [NSString stringWithFormat:@"%02d",secondValue%60];
        NSString *format_time = [NSString stringWithFormat:@"%@:%@:%@",str_hour,str_minute,str_second];
        self.currentTimeLb.text = [NSString stringWithFormat:@"%@",format_time];
    }
    
    - (void)dealloc
    {
        NSLog(@"%s",__func__);
    }
    

    第二、防止暴力点击。点确定按钮提交答案时,为了防止用户暴力点击,所以,点击间隔时间小于1秒的,无效。

    - (IBAction)submitBtnClick:(UIButton *)btn
    {
        DLog(@" %s ",__FUNCTION__);
        [[self class] cancelPreviousPerformRequestsWithTarget:self
                                                     selector:@selector(handleEvent:)
                                                       object:btn];
        [self performSelector:@selector(handleEvent:) withObject:btn afterDelay:1.0];
    }
    
    - (void)handleEvent:(UIButton *)btn
    {}
    

    第三、获取当前题目答案。点击确认提交答案的同时,保存当前题目答案,然后滑动到下一题,我再滑回上一道题的时候,依然可以展示上一道题的答案,self.currentIndex是指当前题目的页码。

    #pragma mark - scrollViewDelegate
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView
    {
        NSInteger index = (scrollView.contentOffset.x+scrollView.frame.size.width*0.5)/scrollView.frame.size.width;
        if (index != self.currentIndex || index == self.defautIndex) {//页面改变了
            // 这里设置成-1  为了index == self.defautIndex 失效
            self.defautIndex = -1;
            
            [self updateAnswers];
            
            self.currentIndex = index;
            DLog(@"index:%zd",index);
        }
    }
    
    #pragma mark 更新暂存的答案
    - (void)updateAnswers{
        
        for (UICollectionViewCell *cell in [self.collectionView visibleCells]) {
            
            HomeBaseExamTV *tableView = cell.contentView.subviews[0];
            
            [self.dataSource enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(HomePowerExamModel *model, NSUInteger idx, BOOL * _Nonnull stop) {
                
                if (model.QuestionBId == [NSString stringWithFormat:@"%@",tableView.answer[@"QuestionBID"]] ) {
                    model.userAnswer = tableView.answer[@"answer"];
                    if ([model.QB_Type isEqualToString:@"3"] && ![model.userAnswer isEqualToString:@""]) {
                        if ([model.userAnswer isEqualToString:@"A"]) {
                            model.userAnswer = @"对";
                        } else
                        {
                            model.userAnswer = @"错";
                        }
                    }
                    DLog(@"答案:%@",model.userAnswer);
                    if (self.currentIndex == self.dataSource.count-1)
                    {
                        [self submitData:model.userAnswer Type:@"1"];
                    } else
                    {
                        [self submitData:model.userAnswer Type:@"0"];
                    }
                }
            }];
        }
    }
    
    //如果是单选题,则对应的是这个方法
    - (NSDictionary *)answer{
        
        if (self.selected != -1)
        {
            return  @{@"QuestionBID":@([self.model.QuestionBId intValue]),@"answer":self.answerList[_selected]};
        } else
        {
             return @{@"QuestionBID":@([self.model.QuestionBId intValue]),@"answer":@""};
        }
    }
    
    //如果是多选题,那answer对应的方法就是快速排序,就是前面MultiTV中的方法
    - (NSDictionary *)answer{
        
        NSString *answer = @"";
        NSString *Answer = @"";
        /*给数组快速排序*/
        [self.selectedArray sortUsingSelector:@selector(compare:)];
        for (NSNumber *number in self.selectedArray) {
            Answer =  [Answer stringByAppendingString:self.multiAnswerList[number.intValue]];
        }
        if (Answer.length > 0) {
            answer = [Answer substringToIndex:[Answer length]-1];
        }
        
        if (answer.length>0)
        {
            return @{@"QuestionBID":@([self.ExModel.QuestionBId intValue]),@"answer":answer};
        } else
        {
            return @{@"QuestionBID":@([self.ExModel.QuestionBId intValue]),@"answer":@""};
        }
    }
    
    总结

    app项目业务开发,更多是涉及到交互逻辑设计,会有很多细节,这些都是经验,对app开发人员来说,在实现的过程中会遇到很多bug,但踩过来了就是经验的提升,记录下来,除了分享,也是对自己的回顾,希望自己能够不断提升,一起加油。

    相关文章

      网友评论

      • b48ecb355cd8:大佬,那题卡放在哪?我的会一起动啊。
        b48ecb355cd8:@行走的苹果哥 大神果然高啊。留个微信,约么?
        行走的苹果哥:你看一下你的界面的层次结构,跟着一起动的话,那有可能你把题卡按钮变成了tableview的子视图了,题卡按钮和列表一样,都是作为self.view的子视图!
      • 溜溜leesin:大佬可不可以借泊学账户下载视频呀
      • 山重水复疑无路:有没有demo 啊
      • Corbin___:数据哪里抓取的
        行走的苹果哥:@陈泽槟 不是,这个例子是公司项目中的,接口也是公司提供的!
        Corbin___:@行走的苹果哥 我就是想问问这个接口数据是免费的吗,提供出来看看可以吗
        行走的苹果哥:@陈泽槟 有接口数据!

      本文标题:iOS开发 • 实例——用CollectionView和tabl

      本文链接:https://www.haomeiwen.com/subject/xjndyxtx.html