高仿喜马拉雅FM(第二弹)

本文分享了一款高仿喜马拉雅APP的开发过程,包括自定义TabBar的隐藏逻辑、播放按钮组件化、使用DZNEmptyDataSet处理空数据状态、一维数组转二维数组的技巧以及YYText框架的应用。

项目地址github:https://github.com/Eastwu5788/XMLYFM 如果您觉得不错,记得给一个star
第一期地址:http://www.jianshu.com/p/3f48a1dccf52 如果您觉得不错,记得给一个喜欢,谢谢

  • 之前的第一弹文章比较长,影响了阅读,所以在这里接着介绍我的高仿喜马拉雅APP的基本情况。这次我将软件运行效果放到了后面,将代码的介绍放到了前面,方便大家阅读。

代码介绍

  1. 由于我的TabBar是自定义的,所以在Push的时候设置hidesBottomBarWhenPushed属性没有效果。应为hidesBottomBarWhenPushed影响的只能是系统的TabBar item。为了解决这个问题需要在TabBar中实现UINavigationController的两个代理方法。当页面即将跳转并且需要影藏TabBar的时候将自己的TabBar设置hidden,当页面跳转回来的时候需要取消影藏,如果在这里稍加点动画效果就能做成与京东app一样的效果。参考内容
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if (viewController.hidesBottomBarWhenPushed) {
        self.bgImageView.hidden = YES;
    }
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    self.tabBar.hidden = YES;
    if (!viewController.hidesBottomBarWhenPushed) {
        self.bgImageView.hidden = NO;

    }
}

2.在很多的子页面中的正下方都有一个播放按钮,这是为了方便进入播放页面提供的东西。如果在每个页面中都写一个这样的按钮就太麻烦了。所以我写了一个"XMLYBasePlayController"类,在这个类中加入了播放按钮,所有想要加入播放按钮的控制器只需要继承该控制器即可。

//播放按钮的视图类
@interface XMLYBasePlayView : UIView
@property (nonatomic, weak) UIButton    *playButton;
@property (nonatomic, weak) UIImageView *bgImageView;
@end

//有音频播放按钮的基类,继承该类可以在控制器下方出现一个播放按钮
@interface XMLYBasePlayController : XMLYBaseController

@property (nonatomic, weak) XMLYBasePlayView *playView;

@end

3.使用的第三方库介绍:DZNEmptyDataSet,这是一个用来处理当UITableView或者UICollectionview无数据时的页面显示情况的三方库。使用挺方便的,当你的页面无数据时,会自动显示空数据情况,让你少了很多逻辑判断。
下面给一个代码里面的使用例子

//1.设置代理
- (void)configEmptyStatus {
    self.tableView.emptyDataSetSource = self;
    self.tableView.emptyDataSetDelegate = self;
}

//2.返回空数据时的占位图,还有很多功能,github上有详细的demo
#pragma mark - DZNEmptyDataSetSource/DZNEmptyDataSetDelegate
- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
    return [UIImage imageNamed:@"noData_play_history"];
}

4.由于接口返回的精品听单列表是一个一维数组,而界面中显示它是一个根据月份区分的二维数组,所以在请求到数据后需要将一维数组转换成二维数组。

/**
 *  将模型转换成二维数组
 */
- (void)dealWithModel:(XMLYListenListModel *)model isRefresh:(BOOL)isRefresh {

    XMLYListenListModel *monthModel;

    if(isRefresh || self.dataSource.count == 0) {
        [self.dataSource removeAllObjects];
        monthModel = [[XMLYListenListModel alloc] init];
    } else {
        monthModel = self.dataSource.lastObject;
    }

    for(NSInteger i = 0, max = model.list.count; i < max; i++) {
        XMLYListenItemModel *itemModel = model.list[i];
        NSString *timeStr = [XMLYTimeHelper dataStringFromTimeInterval:itemModel.releasedAt / 1000 dataFormatter:@"MM/YYYY"];
        //当前月份值不存在,则表示是新数据,直接插入
        if(!monthModel.timeStr || monthModel.timeStr.length == 0) {
            monthModel.timeStr = timeStr;
            [monthModel.list addObject:itemModel];
        //当前月份存在,并且与item的月份相同,则插入
        } else if(monthModel.timeStr && [monthModel.timeStr isEqualToString:timeStr]) {
            [monthModel.list addObject:itemModel];
        } else {
            //老月份加入数组
            [self.dataSource addObject:[monthModel copy]];
            //开启新月份
            monthModel = [[XMLYListenListModel alloc] init];
        }
        //
        if(i == max - 1 && [monthModel.timeStr isEqualToString:timeStr]) {
            [self.dataSource addObject:[monthModel copy]];
        }
    }

    [self.collectionView reloadData];
}

5.如果使用系统的CoreText来完成部分文字的点击功能,或者TTTAtributedLabel,实现起来都稍微有点点麻烦,但是自从有了YYText框架,这一切都变得超简单了。

- (NSMutableAttributedString *)configAnchorLabel:(NSString *)string {
    NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:string];
    text.yy_color = [UIColor colorWithRed:0.58f green:0.59f blue:0.59f alpha:1.00f];
    NSRange range = NSMakeRange(3, string.length - 3);
    [text yy_setTextHighlightRange:range color:Hex(0x5680B9) backgroundColor:[UIColor clearColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
        NSLog(@"taptext:%@",text.string);
    }];
    return text;
}

干货效果演示

音频本地下载、播放功能演示


LocalDownload.gif

音频播放功能演示


PlayDetail.gif

效果演示

小编推荐页面


EditRecom.gif

直播列表页面


LiveList.gif

免流量服务页面


WebServer.gif

精品听单列表页面


GooList.gif

听单详情页面


ListenDetail.gif

专辑详情页面


AlbumDetail.gif

欢迎大家关注我的微信公众号


wechat.jpg
### JavaWeb 实现有声小说平台(类喜马拉雅应用) #### 项目概述 有声小说平台旨在提供在线音频播放服务,允许用户浏览、收听以及管理个人收藏的有声读物。此类应用程序通常具备如下功能模块: - 用户注册与登录验证机制 - 音频资源上传及分类展示 - 搜索栏用于快速查找特定作品 - 收藏夹保存感兴趣的节目列表 - 推荐算法推送个性化内容给听众[^1] #### 技术栈选型 为了构建高效稳定的 Web 应用程序,推荐采用 Spring Boot 框架作为后端开发工具包;前端界面则可以选用 Vue.js 或 React 来增强交互体验。数据库方面建议使用 MySQL 存储结构化数据,Redis 缓存热数据以提高访问速度。 #### 关键组件设计 ##### 后端 API 设计 定义 RESTful APIs 处理客户端请求并返回 JSON 数据响应。以下是几个重要的接口示例: - **获取首页轮播图** ```http GET /api/v1/carousels ``` - **查询所有专辑** ```http GET /api/v1/albums?category={categoryId}&page={pageNum} ``` - **根据 ID 获取单个专辑详情** ```http GET /api/v1/album/{id} ``` - **提交评论** ```http POST /api/v1/comments Content-Type: application/json { "userId": 1, "contentId": 203, "text": "这本小说真不错" } ``` ##### 前端页面布局 利用 HTML5 和 CSS3 构建美观易用的操作面板,确保良好的跨浏览器兼容性和移动端适配效果。对于复杂业务逻辑部分可借助 JavaScript ES6+ 特性简化编码工作量。 ```html <!-- index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"/> <title>有声书城</title> <link rel="stylesheet" href="./assets/css/style.css"/> <script src="./assets/js/app.bundle.js"></script> </head> <body> <div id="app"></div> </body> </html> ``` ##### 客户端 SDK 开发 针对不同操作系统定制专属 App Store 下载链接按钮,方便新老客户下载安装官方移动版客户端软件。同时开放第三方开发者接入权限,鼓励更多创新应用场景涌现出来。 #### 示例代码片段 下面给出一段简单的 Spring Boot 控制器方法来处理获取指定编号章节的功能: ```java @RestController @RequestMapping("/chapters") public class ChapterController { @Autowired private IChapterService chapterService; /** * 根据ID查询章节信息. */ @GetMapping("/{chapterId}") public ResponseEntity<ChapterDTO> get(@PathVariable Long chapterId){ try{ Optional<ChapterEntity> optional = chapterService.findById(chapterId); if(!optional.isPresent()){ throw new ResourceNotFoundException("未找到该章节"); } return ResponseEntity.ok(new ChapterDTO(optional.get())); }catch (Exception e){ log.error(e.getMessage(),e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } } ``` 通过上述描述可以看出,在 JavaWeb 平台上创建类似于喜马拉雅这样的大型多媒体分享社区并非难事,只要合理规划架构方案和技术路线即可达成目标。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值