第十八篇玩转【斗鱼直播APP】系列之娱乐菜单展示

本文介绍了一种娱乐菜单界面的设计方案,对比了使用UIScrollView与UICollectionView的不同布局思路,最终选择了UICollectionView嵌套UICollectionView的方式,实现了循环利用视图组件并保持良好的排版效果。

娱乐菜单展示

效果展示

  • 如图

思路分析

  • 该界面其实非常常见,像微信聊天中就有类似的界面
  • 该界面如何布局呢?
思路一:UIScrollView
  • 整体是一个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
  1. fileprivate lazy var menuView : AmuseMenuView = {
  2. let menuView = AmuseMenuView.amuseMenuView()
  3. menuView.frame = CGRect(x: 0, y: -kMenuViewH, width: kScreenW, height: kMenuViewH)
  4. return menuView
  5. }()
  • 添加到UICollectionView中,并且设置UICollectionView的内边距
  1. override func setupUI() {
  2. super.setupUI()
  3. collectionView.addSubview(menuView)
  4. collectionView.contentInset = UIEdgeInsets(top: kMenuViewH, left: 0, bottom: 0, right: 0)
  5. }
  • 实现UICollectionView的数据源&代理
    • 实现数据源方法,展示数据
    • 注册Cell(在awakeFromNib中注册)
    • 设置布局(在layoutSubviews中设置,该位置可以拿到正确的尺寸)
  1. import UIKit
  2. private let kMenuCellID = "kMenuCellID"
  3. class AmuseMenuView: UIView {
  4. // MARK: 控件属性
  5. @IBOutlet weak var collectionView: UICollectionView!
  6. @IBOutlet weak var pageControl: UIPageControl!
  7. // MARK: 从Xib中加载出来
  8. override func awakeFromNib() {
  9. super.awakeFromNib()
  10. collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: kMenuCellID)
  11. }
  12. override func layoutSubviews() {
  13. super.layoutSubviews()
  14. let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
  15. layout.itemSize = collectionView.bounds.size
  16. }
  17. }
  18. // MARK:- 提供快速创建的类方法
  19. extension AmuseMenuView {
  20. class func amuseMenuView() -> AmuseMenuView {
  21. return Bundle.main.loadNibNamed("AmuseMenuView", owner: nil, options: nil)?.first as! AmuseMenuView
  22. }
  23. }
  24. // MARK:- 遵守UICollectionView的数据源&代理协议
  25. extension AmuseMenuView : UICollectionViewDataSource, UICollectionViewDelegate {
  26. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  27. return 2
  28. }
  29. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  30. // 1.取出Cell
  31. let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kMenuCellID, for: indexPath)
  32. cell.backgroundColor = UIColor.randomColor()
  33. return cell
  34. }
  35. }
  • 自定义Cell,用于展示每一个Item
    • 在Cell中添加UICollectionView
    • 设置UICollectionView的数据源&代理
    • 注册Cell(在awakeFromNib中注册)
    • 设置布局(在layoutSubviews中设置,该位置可以拿到正确的尺寸
  1. import UIKit
  2. private let kGameCellID = "kGameCellID"
  3. class AmuseMenuViewCell: UICollectionViewCell {
  4. @IBOutlet weak var collectionView: UICollectionView!
  5. override func awakeFromNib() {
  6. super.awakeFromNib()
  7. collectionView.register(UINib(nibName: "CollectionGameCell", bundle: nil), forCellWithReuseIdentifier: kGameCellID)
  8. }
  9. override func layoutSubviews() {
  10. super.layoutSubviews()
  11. let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
  12. let itemW = collectionView.bounds.width / 4
  13. let itemH = collectionView.bounds.height / 2
  14. layout.itemSize = CGSize(width: itemW, height: itemH)
  15. }
  16. }
  17. extension AmuseMenuViewCell : UICollectionViewDataSource, UICollectionViewDelegate {
  18. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  19. return 8
  20. }
  21. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  22. let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kGameCellID, for: indexPath)
  23. cell.backgroundColor = UIColor.randomColor()
  24. return cell
  25. }
  26. }
  • 展示数据
    • AmuseMenuView定义[GameBaseModel]属性
    • 监听属性的改变,将数据每8个传递给Cell一次
    • Cell拿到数据,将数据展示到GameCell中即可
    • 代码叫简单(此处不再粘贴)
在车辆工程中,悬架系统的性能评估和优化一直是研究的热点。悬架不仅关乎车辆的乘坐舒适性,还直接影响到车辆的操控性和稳定性。为了深入理解悬架的动态行为,研究人员经常使用“二自由度悬架模型”来简化分析,并运用“传递函数”这一数学工具来描述悬架系统的动态特性。 二自由度悬架模型将复杂的车辆系统简化为两个独立的部分:车轮和车身。这种简化模型能够较准确地模拟出车辆在垂直方向上的运动行为,同时忽略了侧向和纵向的动态影响,这使得工程师能够更加专注于分析与优化与垂直动态相关的性能指标。 传递函数作为控制系统理论中的一种工具,能够描述系统输入和输出之间的关系。在悬架系统中,传递函数特别重要,因为它能够反映出路面不平度如何被悬架系统转化为车内乘员感受到的振动。通过传递函数,我们可以得到一个频率域上的表达式,从中分析出悬架系统的关键动态特性,如系统的振幅衰减特性和共振频率等。 在实际应用中,工程师通过使用MATLAB这类数学软件,建立双质量悬架的数学模型。模型中的参数包括车轮质量、车身质量、弹簧刚度以及阻尼系数等。通过编程求解,工程师可以得到悬架系统的传递函数,并据此绘制出传递函数曲线。这为评估悬架性能提供了一个直观的工具,使工程师能够了解悬架在不同频率激励下的响应情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值