一、主要控制器介绍
一级模块 | 二级模块 | 对应控制器 |
---|---|---|
课程列表 | 主控制器 | XLInsideCourseListViewController |
课程列表 | 下拉筛选框 | XLEnterpriseCourseListShowMoreTypeView |
课程详情 | 主控制器 | XLHomeCourseDeailController |
课程详情 | 章节列表子控制器 | XLCourseContentViewController |
课程详情 | 课程评论子控制器 | XLCourseChatViewNewController |
课程详情 | 课程介绍子控制器 | XLCourseChatViewController |
二、主要跳转逻辑
三、接口请求
所属模块 | 接口描述 | 接口关键字 |
---|---|---|
课程列表 | 获取筛选框列表数据 | InsideCourseTypeList |
课程列表 | 根据筛选框获取课程列表数据 | requestEnterpriseCourseWithCourseTypeID |
课程详情 | 获取课程详情 | xlcourseGetChapterWare |
课程详情 | 更新课件观看进度 | xlupdateStudyCourseProgress |
课程介绍 | 获取推荐课程 | CourseRecommendList |
课程章节 | 获取课件目录 | xlcourseGetChapterWareList |
课程章节 | 判断课程是否加入考试 | xlcourseJoinExam |
课程章节 | 获取课程分组 | xlcourseGetChapters |
课程章节 | 获取分组下课件目录 | xlcourseGetChapterWareList |
课程章节 | 获取课件详情 | xlcourseGetChapterWare |
课程章节 | 更新课件观看进度 | xlupdateStudyCourseProgress |
评论 | 获取评论列表 | xlcourseComments |
评论 | 添加课程评论 | xlcourseAddComent |
评论 | 添加回复评论 | xlcourseReplyComent |
评论 | 点赞或取消 | xlcourseLiked |
四、代码设计
1.课程列表
①.页面设计
主要页面有以下几个
页面描述 | 页面名称 |
---|---|
列表页 | tableView |
筛选框 | moreTypeView |
顶部已选择分类 | collectionView |
②.关键代码逻辑与设计
进入课程列表后,请求接口有两个:
//获取下级列表
- (void)loadCourseNextTypeList:(XLClassifyModel *)clasfyModel{
[self.typeArray removeAllObjects];
NSDictionary *parmDict=@{@"parentId":@(clasfyModel.CourseTypeID),@"name":@""};
[[XLNetworkManager sharedManager] InsideCourseTypeList:parmDict progress:nil success:^(XLResponse * _Nonnull xlResponse) {
if (xlResponse.successDataObject) {
NSArray *secArray= xlResponse.successDataObject;
[secArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
__block XLClassifyModel *cModel=[XLClassifyModel modelWithDictionary:obj];
[self.typeArray addObject:cModel];
}];
if (self.moreTypeView) {
[self.moreTypeView reloadAllData:nil];
}
}
} failure:^(XLResponsError * _Nonnull error) {
} formate:nil];
}
//获取课程列表
- (void)loadData {
_pageIndex = 1;
[[XLNetworkManager sharedManager] requestEnterpriseCourseWithCourseTypeID:_courseTypeID CourseClassifyID:@"" Keyword:@"" DepartmentID:@"0" PageIndex:@(_pageIndex).stringValue andType:@"0" success:^(XLResponse * _Nonnull xlResponse) {
self.dataListArray = [NSMutableArray arrayWithArray:xlResponse.dataObject[@"Data"]];
if (self.dataListArray.count > 0) {
self.tableView.hidden = NO;
self.emptyView.hidden = YES;
[self.tableView reloadData];
[self.tableView.mj_header endRefreshing];
if (self.dataListArray.count < 10) {
[self.tableView.mj_footer endRefreshingWithNoMoreData];
}else{
[self.tableView.mj_footer endRefreshing];
}
}else{
self.tableView.hidden = YES;
self.emptyView.hidden = NO;
}
} failure:^(XLResponsError * _Nonnull error) {
}];
}
当用户"点击下级分类"弹出筛选界面,再次点击某一分类操作时会触发回调方法:
- (void)selectTypeModel:(XLClassifyModel *)xlmodel isLoadList:(BOOL )loadList{
}
并且进行下级子分类的数据请求
//获取下级列表
- (void)loadCourseNextTypeList:(XLClassifyModel *)clasfyModel{
[self.typeArray removeAllObjects];
NSDictionary *parmDict=@{@"parentId":@(clasfyModel.CourseTypeID),@"name":@""};
[[XLNetworkManager sharedManager] InsideCourseTypeList:parmDict progress:nil success:^(XLResponse * _Nonnull xlResponse) {
if (xlResponse.successDataObject) {
NSArray *secArray= xlResponse.successDataObject;
[secArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
__block XLClassifyModel *cModel=[XLClassifyModel modelWithDictionary:obj];
[self.typeArray addObject:cModel];
}];
if (self.moreTypeView) {
[self.moreTypeView reloadAllData:nil];
}
}
} failure:^(XLResponsError * _Nonnull error) {
} formate:nil];
}
如有下级子分类:“继续筛选下一级”按钮为可点击状态。
如无下级子分类:“继续筛选下一级”按钮为不可点击状态。
点击确认选择:通过选中分类再次进行列表数据请求,刷新tableview。
2.课程详情
①.页面设计
主要页面有以下几个
页面描述 | 页面名称 | 备注 |
---|---|---|
顶部视频或者文档显示区域 | courseTopHeadView | |
三个切换tab | scrollTabView | |
pageviewcontroller内容 | subContentView | |
课程介绍 | courceSumViewController | 子控制器 |
课程目录 | courseContentViewController | 子控制器 |
课程评论 | courseChatViewController | 子控制器 |
②.关键代码逻辑与设计
- 进入课程播放页,请求课程详情
//获取课程详情
-(void)loadCourseDetail:(NSInteger)courseid
{
[[XLNetworkManager sharedManager] xlcourseEnterpriseDetail:@{@"courseID":[NSNumber numberWithInteger:self.courseId?self.courseId:0]} progress:nil success:^(XLResponse * _Nonnull xlResponse) {
XLLog(@"%@",(NSArray *)xlResponse.successDataObject);
if (xlResponse.successDataObject) {
NSDictionary *backDict=(NSDictionary*)xlResponse.successDataObject;
self.courseModel=[XLCourseModel modelWithClassDic:backDict[@"c"] modelClass:@"XLCourseModel"];
self.courseTopHeadView.dataModel=self.courseModel;
// 刷新简介和标题
XLCourceSumViewController *sumViewController=(XLCourceSumViewController *)self.ctrollerArray[0];
[sumViewController freshView:self.courseModel];
XLLog(@"%@",xlResponse.successDataObject);
}else{
if ([xlResponse.responseError.errMsg isEqualToString:@"权限错误"]) {
[XLHudManager showTextWithNoimage:@"该课程已下架"];
[self noDataAction];
}else{
[XLHudManager showTextWithNoimage:xlResponse.responseError.errMsg];
}
}
} failure:^(XLResponsError * _Nonnull error) {
} formate:nil];
}
获取课程目录
//课程目录相关的东西
-(void)loadCourseCata:(NSInteger)courseid
{
[[XLNetworkManager sharedManager] xlcourseGetChapters:@{@"courseID":[NSNumber numberWithInteger:courseid]} progress:nil success:^(XLResponse * _Nonnull xlResponse) {
XLLog(@"%@",(NSArray *)xlResponse.successDataObject);
if (xlResponse.successDataObject) {
NSArray *backArray=(NSArray*)xlResponse.successDataObject;
if (backArray.count>0) {
NSDictionary *dict=backArray[0];
XLCourseCataModel *model=[XLCourseCataModel modelWithClassDic:dict modelClass:@"XLCourseCataModel"];
[self loadCourseWareList:model.ChapterID section:0];
}
}else{
[XLHudManager showTextWithNoimage:xlResponse.responseError.errMsg];
}
} failure:^(XLResponsError * _Nonnull error) {
} formate:nil];
}
根据请求的数据,头部视图显示对应内容,如果是pdf或world课件,隐藏视频播放器,点击后跳转课件浏览器。如果是视频、音频,则显示视频播放器,并且自动播放视频、音频 。相关代码逻辑请查看此方法:
- (void)setWareModel:(XLChapWareModel *)wareModel
{
}
首次进入课程详情页,为了优化用户体验,目录、评论子控制器不会请求数据。当用户左右滑动到目录、评论对应子控制器时候,才会进行对应数据请求及页面逻辑显示。
章节目录
默认展开第一个分组,且只展开一个分组。
首页判断是否加入考试,以此来控制底部“课后测试”按钮的显示与隐藏。相关代码逻辑请查看此方法:
#pragma mark 判断是否加入考试
-(void)examJudge{
}
主要接口请求有以下两个方法:
//获取课程分组
-(void)loadCourseCata:(NSInteger)courseid
{
}
//获取分组下课件目录
-(void)loadCourseWareList:(NSInteger)chapterId section:(NSInteger)loadSection
{
}
cell点击逻辑:如果是pdf或者world文档,点击cell即视为该课程学习完成,调用更新课程进度方法,并且刷新UI,课件变为已完成阅读状态。更新课件进度方法如下(内部逻辑省略,请自行查看):
#pragma mark更新进度
-(void)updateProgressWithCourseID:(NSInteger)courseID model:(XLChapWareModel *)model cataModel:(XLCourseCataModel*)cataModel index:(NSInteger)index{
}
如果是视频课件,视频播放完毕后会接收到来自主控制的通知事件,更新UI,课件变为已完成状态
//接收通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeChannelNoti:) name:@"PlayDone" object:nil];
//通知调用方法
#pragma mark视频播放完成
- (void)changeChannelNoti:(NSNotification *)noti
{
XLChapWareModel *model = [XLChapWareModel new];
model = self.curWareModel;
model.enpriseProgressModel.Progress = 100;
[self.readArr addObject:model];
[self.contentTableView reloadData];
}
课件名称如果过长,则自动滚动,逻辑在XLCourseConTableCell子视图
label自动滚动控件为QWorseRaceLamp
固定课件名称label宽度为200
#define titleLabelWidth 200
根据课件的字符串转化成长度,对比字符串长度以及label最大宽度,控制课件名称是否自动滚动,关键代码如下:
if (self.mainWidth > titleLabelWidth) {
[self.animationLabel startAnimation];
}
- 评论
评论控制器设计成依靠tableview实现
评论区分一级评论和二级评论,其中:一级评论为用户对课程直接评论,二级评论是用户对用户评论。
自定义头部视图用于显示一级评论,cell用于显示二级评论。
二级评论默认只展示一条数据,如有多条数据,点击‘展开更多回复内容’,显示全部二级评论,对应逻辑如下:
#pragma mark 展开更多
-(void)showMoreReplyButtonActionWithSection:(NSInteger)section row:(NSInteger)row{
[self.unFoldArray addObject:[NSNumber numberWithInteger:section]];
[self.mainTableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
}
发表评论区分课程评论和回复评论:
课程评论实现为如下方法:
#pragma mark 添加课程评论
-(void)addAplyCommonActionWith:(NSString *)content{
}
回复评论参考如下方法:
-(void)addAplyUserActionWithContent:(NSString *)content model:(XLReplyModel *)model{
}
点赞的接口实现在对应的view中,动画实现及UI刷新在评论主控制器中实现。
#pragma mark 头部视图点赞
-(void)likeButtonActionWithSection:(NSInteger)section{
NSLog(@"点赞第%ld行",section);
[UIView setAnimationsEnabled:NO]; // 或者[UIView setAnimationsEnabled:NO];
[self.mainTableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];
[UIView setAnimationsEnabled:YES]; // 或者[UIView setAnimationsEnabled:YES];
}
#pragma mark cell点赞
-(void)likeButtonActionWithSection:(NSInteger)section row:(NSInteger)row{
[UIView setAnimationsEnabled:NO]; // 或者[UIView setAnimationsEnabled:NO];
NSLog(@"点赞第%ld行 第%ld个",section,row);
[self.mainTableView reloadRow:row inSection:section withRowAnimation:UITableViewRowAnimationNone];
[UIView setAnimationsEnabled:YES]; // 或者[UIView setAnimationsEnabled:YES];
}
点赞动画不能在子视图中实现,子视图传递代理方法,将点赞按钮对于主屏幕的坐标传递给主控制器
#pragma mark 头部点赞动画
-(void)headerLikeAnimationWithRect:(CGRect)rect{
[self zanAnimationWithRect:rect];
}
#pragma mark cell点赞动画
-(void)likeAnimationWithRect:(CGRect)rect{
[self zanAnimationWithRect:rect];
}