前言
网易云音乐是一款很优秀的音乐软件,我也是它的忠实用户。最近在研究如何更好的开发TableView,接着我写了一个Model驱动的小框架 - MDTable。为了去验证框架的可用性,我选择了网易云音乐的首页来作为Demo,语言是Swift 3。
本文的内容包括:
- 实现网易云音乐首页的思路
- 如何建立一个轻量级的
UITableViewController
(不到100行) - 性能瓶颈原因以分析及如何优化到接近60fps
Note:本文并没有用Reveal去分析网易云音乐iOS客户端的原始UI布局,所以实现方式肯定和原始App有出入。另外,本文仅代表个人观点,与雇主没有任何关系。
最后效果如下
容器
整体上分析来看,网易云音乐的首页是一个异构的滚动视图。由上至下依次是:
- Banner - 轮播
- Menu - 三个入口
- 6个分类,推荐歌单,独家放送,推荐MV,精选专栏,主播电台,最新音乐。每一个分类的UI布局都不一样。
并且这些布局都不是动态的,所谓动态的就是向淘宝京东首页那种,做不同的活动,首页可以按照不同的方式去显示内容,而不需要从App Store下载新的版本。
基于这些,有两种实现方式:
用单纯的UIScrollView作为容器,其他的内容作为SubView添加到ScrollView中,但要手动控制每一个视图进入屏幕和消失的事件,来进行图片的懒加载。采用这种方式可以选择天猫开源的LazyScrollView
用UITableView作为容器,其他的每一行内容都是一个Cell。
本文选择了后者,原因也很简单:我是为了评估MDTable,而MDTable是一个基于TableView的框架。
Banner
网易云音乐Banner的最上面是一个轮播图,效果如下
可以看到视图大致分为两部分:
- ScrollView - 容器
- ItemView - 轮播的具体内容
- ImageView - 背景图
- Label - 标签,就是图中的广告部分。
轮播图有很多种实现方式,这里我选择了之前写的ParallexBanner。
这是一个支持视差效果的Banner,所谓视差效果,就是类似这种:
ParallexBanner原理我在这篇博客里有详细介绍,这里就不浪费篇幅了。
另外,那个标签Label也很容易实现,只要用一个左边是圆角的UILabel即可,这里写了个方便的扩展
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
Menu
Menu的目标效果如下:
中间的“每日歌曲推荐”这个选项有点意思,因为中间的文字是会随着日期变的。实现起来也很简单,图片留白,中间放一个Lable即可。
这是最后我选择的布局方式:
侧面看起来:
也就是说,SubView是这样子的:
- UIImageView - 红色背景圆圈
- UILabel - 标题(每日歌曲推荐)
- UIImageView - 图标(日历图标)
- UILabel - 日期时间(25)
Note: 这里先不管按下态,按下态在下文统一讲解。
Cells
我们先从UI效果入手,一共有六种异构的Cell。
第一个冒出来的想法是Cell中放置CollectionView,CollectiionViewLayout也很简单,采用系统提供的FlowLayout即可。
图个省事,每一个CollectionViewCell我都采用Xib的方式,用AutoLayout布局的。