MVC是一种设计模式 面试的时候也经常被问到 一般都会说Model-View-Controller三者的关系 今天没事 就写篇文章 用实际的开发运用MVC
先看效果图
这是个答题的页面 首先进来 请求接口 返回 顶部的轮播图图片数组 中间的标题 中间的内容 答题奖励价格 投放和剩余数量等等信息 还有下面的题目信息 然后底部有一个提交按钮 提交答案
很典型的 接口--- 展示数据----提交数据的 常见开发场景
首先页面分解 下面的答题的题目和答案 可以采用tableview去布局 那么顶部的(轮播图及具体信息)就是一个view 当做tableview的headerview 底部的提交按钮就是tableview的footerview
所以第一步 先把顶部的部分封成一个View
里面的控件就这么多 都声明下 然后 设置控件的属性
值得注意的是内容的label需要把numberOfLines设置为0
然后就是基本的masonry布局
根据接口数据创建model 然后在控制器里去请求数据 然后转成model 设置给这个view
在model的set方法里 给view的控件赋值
[图片上传中...(image.png-7cee49-1532678118564-0)]
/**
根据接口返回数据去设置头视图
@param model 大的模型
*/
- (void)setUpHeaderViewWith:(SHAdverDetailModel *)model
{
NSString *introduce = model.introduce;
CGRect rect = [introduce boundingRectWithSize:CGSizeMake(SHScreenW - 26, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:13.f ]} context:nil];
SHAnswerHeaderView *headerView = [[SHAnswerHeaderView alloc]initWithFrame:CGRectMake(0, 0, SHScreenW, 315 + rect.size.height)];
headerView.model = model;
self.tableView.tableHeaderView = headerView;
}
其中boundingRectWithSize是手动计算内容高度的方法
这样就把一个带有接口数据的动态高度的view设置成了tableview的头视图
控制器里的代码此时有 发起网络请求 ---- 拿到数据 ---- 创建头视图
然后分析需要解决的点
1:轮播图下方内容高度不固定 高度随内容的增长而增长 (上面已解决)
2:题目的选择 单选 及 选中效果
3:如何优雅的传入数据拿到每道题选择的答案
下面的题目布局 分析下 每个题目作为一个section 题目是section的headerView(自定义的view 需要传入 下标 和 题目字符串) 每条答案是cell (其中前面的选中效果需要控制蓝色view的显示与隐藏 ) 至于选择一个答案之后需要取消上一个选中及设置当前选中 我们可以在题目的model里面自定义一个字段
上面的5个字段是接口返回的题目和答案 还有正确选项
我添加一个字段
//选择的下标 默认为-1
@property (nonatomic, assign) NSInteger seleteIndex;
然后在model的init方法里给默认值-1
- (instancetype)init
{
if (self = [super init]) {
self.seleteIndex = -1;
}
return self;
}
这个值的意思是我选中的是第几个答案
然后在cell的.h里暴露一个布尔值和字符串
#pragma mark --- setting
- (void)setIsSelete:(BOOL)isSelete
{
_isSelete = isSelete;
if (isSelete) {
self.smallCycleView.hidden = NO;
}else{
self.smallCycleView.hidden = YES;
}
}
- (void)setQustionStr:(NSString *)qustionStr
{
_qustionStr = qustionStr;
self.answerL.text = qustionStr;
}
在set方法里去控制蓝色区域的显示与隐藏
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
SHAnswerItemModel *model = self.problemsList[indexPath.section];
model.seleteIndex = indexPath.row;
self.problemsList[indexPath.section] = model;
NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:indexPath.section];
[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
}
然后在cell的点击方法里 找到题目的model 把自定义的数据换成cell的下标再赋给model
再调tableview刷新单个section的方法
在cellforrow方法里
如果cell的下标 等于对应model的seleteIndex 就代表是选中的那个cell 所以这个cell要被选择 其他的不被选择
第二个问题也解决了
第三个问题 如何优雅的传入数据拿到每道题选择的答案
因为接口返回了正确答案 所以 我本地就可以判断回答对了几个 哪几个回答对了
在题目的model里面依然自定义一个字段
//是否选择正确 重写get方法
@property (nonatomic, assign) BOOL isCorrect;
重写get方法
- (BOOL)isCorrect
{
switch (self.seleteIndex) {
case 0:
if ([self.correctResponse isEqual:@"A"]) {
return YES;
}
break;
case 1:
if ([self.correctResponse isEqual:@"B"]) {
return YES;
}
break;
case 2:
if ([self.correctResponse isEqual:@"C"]) {
return YES;
}
break;
default:
break;
}
return NO;
}
下标0对应着返回的”A“
最后收尾的就是把提交的view也封成一个view 把按钮点击的事件通过block传出来
最后在提交的方法里
for (int i = 0; i < self.problemsList.count; i ++) {
SHAnswerItemModel *model = self.problemsList[i];
if (model.seleteIndex == -1) {
NSLog(@"题目必须全部作答");
return;
}
NSString *str = model.isCorrect ? @"答对了" : @"答错了";
NSLog(@"第%ld题%@,正确答案%@,你选择了第%ld个",i,str,model.correctResponse,model.seleteIndex);
}
第几题 是否正确 选择的答案 正确答案都一目了然
最后看下控制器的代码
@interface SHAnswerQuesVController ()
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *problemsList;
@end
@implementation SHAnswerQuesVController
#pragma mark --- lazying
- (NSMutableArray *)problemsList
{
if (!_problemsList) {
_problemsList = [[NSMutableArray alloc]init];
}
return _problemsList;
}
- (UITableView *)tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc]initWithFrame:CGRectZero style:UITableViewStyleGrouped];
_tableView.backgroundColor = [UIColor whiteColor];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:_tableView];
}
return _tableView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self layout];
self.navigationItem.title = @"点点答题";
[self loadAdvertiseDetailData];
}
- (void)layout
{
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.bottom.top.mas_equalTo(self.view);
}];
SHAnswerFooterView *footerView = [[SHAnswerFooterView alloc]initWithFrame:CGRectMake(0, 0, SHScreenW, 100)];
__weak __typeof(&*self) weakSelf = self;
footerView.commitBlock = ^{
//点击提交
[weakSelf commit];
};
self.tableView.tableFooterView = footerView;
}
- (void)loadAdvertiseDetailData
{
SHLog(@"%d", _listModel.ID)
SHWeakSelf
NSDictionary *dic = @{
@"adId":@(_listModel.ID)
};
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[[SG_HttpsTool sharedSG_HttpsTool] postWithURL:SHAdverDetailUrl params:dic success:^(id JSON, int code, NSString *msg) {
SHLog(@"%d", code)
SHLog(@"%@", JSON)
[MBProgressHUD hideHUDForView:weakSelf.view];
if (code == 0) {
NSDictionary *responDict = (NSDictionary *)JSON;
NSDictionary *ad = responDict[@"ad"];
SHAdverDetailModel *model = [SHAdverDetailModel mj_objectWithKeyValues:ad];
#warning test 测试长度很多的时候高度的变化
// self.model.introduce = @“一个很长的字符串”
self.problemsList = [SHAnswerItemModel mj_objectArrayWithKeyValuesArray:model.problems];
[self setUpHeaderViewWith:model];
[self.tableView reloadData];
}
} failure:^(NSError *error) {
}];
}
/**
根据接口返回数据去设置头视图
@param model 大的模型
*/
- (void)setUpHeaderViewWith:(SHAdverDetailModel *)model
{
NSString *introduce = model.introduce;
CGRect rect = [introduce boundingRectWithSize:CGSizeMake(SHScreenW - 26, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:13.f ]} context:nil];
SHAnswerHeaderView *headerView = [[SHAnswerHeaderView alloc]initWithFrame:CGRectMake(0, 0, SHScreenW, 315 + rect.size.height)];
headerView.model = model;
self.tableView.tableHeaderView = headerView;
}
//提交
- (void)commit
{
for (int i = 0; i < self.problemsList.count; i ++) {
SHAnswerItemModel *model = self.problemsList[i];
if (model.seleteIndex == -1) {
NSLog(@"题目必须全部作答");
return;
}
NSString *str = model.isCorrect ? @"答对了" : @"答错了";
NSLog(@"第%ld题%@,正确答案%@,你选择了第%ld个",i,str,model.correctResponse,model.seleteIndex);
}
}
#pragma mark --- UITableViewDelegate, UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.problemsList.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SHSeleteAnswerCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([SHSeleteAnswerCell class])];
if (!cell) {
cell = [[SHSeleteAnswerCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NSStringFromClass([SHSeleteAnswerCell class])];
}
SHAnswerItemModel *model = self.problemsList[indexPath.section];
NSString *qustionStr;
switch (indexPath.row) {
case 0:
qustionStr = [NSString stringWithFormat:@"A:%@",model.answerA];
break;
case 1:
qustionStr = [NSString stringWithFormat:@"B:%@",model.answerB];
break;
case 2:
qustionStr = [NSString stringWithFormat:@"C:%@",model.answerC];
break;
default:
break;
}
cell.qustionStr = qustionStr;
if (indexPath.row == model.seleteIndex) {
cell.isSelete = YES;
}else{
cell.isSelete = NO;
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 30;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
SHAnswerItemModel *model = self.problemsList[section];
SHAnswerSectionHeaderView *sectionHeaderView = [[SHAnswerSectionHeaderView alloc]initWithFrame:CGRectMake(0, 0, SHScreenW, 30) section:section quesionStr:model.question];
sectionHeaderView.backgroundColor = [UIColor whiteColor];
return sectionHeaderView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 30;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [UIView new];
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 0.01;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
SHAnswerItemModel *model = self.problemsList[indexPath.section];
model.seleteIndex = indexPath.row;
self.problemsList[indexPath.section] = model;
NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:indexPath.section];
[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
}
一共200行不到