娱乐菜单展示
效果展示
- 如图

思路分析
- 该界面其实非常常见,像微信聊天中就有类似的界面

- 该界面如何布局呢?
- 整体是一个UIScrollView
- 在UIScrollView中多页View
- 在每页View中添加8个按钮
- 缺点:
- 如果数据较多,则无法做到循环利用
- 需要计算每一个按钮的位置
思路二:UICollectionView
- 整体是一个UICollectionView
- 每一个按钮是一个Cell
- 滚动方向为水平滚动(水平滚动时,则会从左到右依次排布)
- 缺点:
- 如果某业数据较少,排布方式会是上下排布
- 而不是先排布第一排,后排布第二排
- 如图

思路三:UICollectionView的Cell中嵌套UICollectionView
- 整体是一个UICollectionView
- 一个Cell为一页
- 一页中防止一个UICollectionView
- 该UICollectionView中放8个数据(如果达到8个,不足8个则水平依次排列)
界面实现
- 自定义AmuseMenuView,用于描述整个顶部菜单
- 该View中主要有一个UICollectionView,一个UIPageControl
- 可以直接通过一个Xib来描述

- 在控制器中加载该View,并且添加到UICollectionView中
- 懒加载AmuseMenuView
fileprivate lazy var menuView : AmuseMenuView = { let menuView = AmuseMenuView.amuseMenuView() menuView.frame = CGRect(x: 0, y: -kMenuViewH, width: kScreenW, height: kMenuViewH) return menuView }()
- 添加到UICollectionView中,并且设置UICollectionView的内边距
override func setupUI() { super.setupUI() collectionView.addSubview(menuView) collectionView.contentInset = UIEdgeInsets(top: kMenuViewH, left: 0, bottom: 0, right: 0) }
- 实现UICollectionView的数据源&代理
- 实现数据源方法,展示数据
- 注册Cell(在awakeFromNib中注册)
- 设置布局(在layoutSubviews中设置,该位置可以拿到正确的尺寸)

import UIKitprivate let kMenuCellID = "kMenuCellID"class AmuseMenuView: UIView { // MARK: 控件属性 @IBOutlet weak var collectionView: UICollectionView! @IBOutlet weak var pageControl: UIPageControl! // MARK: 从Xib中加载出来 override func awakeFromNib() { super.awakeFromNib() collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: kMenuCellID) } override func layoutSubviews() { super.layoutSubviews() let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout layout.itemSize = collectionView.bounds.size }}// MARK:- 提供快速创建的类方法extension AmuseMenuView { class func amuseMenuView() -> AmuseMenuView { return Bundle.main.loadNibNamed("AmuseMenuView", owner: nil, options: nil)?.first as! AmuseMenuView }}// MARK:- 遵守UICollectionView的数据源&代理协议extension AmuseMenuView : UICollectionViewDataSource, UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 2 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // 1.取出Cell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kMenuCellID, for: indexPath) cell.backgroundColor = UIColor.randomColor() return cell }}
- 自定义Cell,用于展示每一个Item
- 在Cell中添加UICollectionView
- 设置UICollectionView的数据源&代理
- 注册Cell(在awakeFromNib中注册)
- 设置布局(在layoutSubviews中设置,该位置可以拿到正确的尺寸

import UIKitprivate let kGameCellID = "kGameCellID"class AmuseMenuViewCell: UICollectionViewCell { @IBOutlet weak var collectionView: UICollectionView! override func awakeFromNib() { super.awakeFromNib() collectionView.register(UINib(nibName: "CollectionGameCell", bundle: nil), forCellWithReuseIdentifier: kGameCellID) } override func layoutSubviews() { super.layoutSubviews() let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout let itemW = collectionView.bounds.width / 4 let itemH = collectionView.bounds.height / 2 layout.itemSize = CGSize(width: itemW, height: itemH) }}extension AmuseMenuViewCell : UICollectionViewDataSource, UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 8 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kGameCellID, for: indexPath) cell.backgroundColor = UIColor.randomColor() return cell }}
- 展示数据
- AmuseMenuView定义[GameBaseModel]属性
- 监听属性的改变,将数据每8个传递给Cell一次
- Cell拿到数据,将数据展示到GameCell中即可
- 代码叫简单(此处不再粘贴)
