本帖最后由 王红元老师 于 2016-9-14 21:25 编辑

布局首页分析实现

完成最终效果

  • 这个效果还是挺常见的哈
  • 效果分析:
    • 顶部是一个工具类,并且为了该工具类可以复用。(其他界面也用到)最好是单独封装起来
    • 中间内容可以左右滚动,并且有分页效果。可以通过封装UIView,并且里面添加UICollectionView方式。

封装顶部的PageTitleView

封装构造函数

  • 封装构造函数,让别人在创建对象时,就传入其实需要显示的内容

    • frame:创建对象时确定了frame就可以直接设置子控件的位置和尺寸
    • isScrollEnable:是否可以滚动。某些地方该控件是可以滚动的。
    • titles:显示的所有标题
       
  1. // MARK:- 构造函数
  2. init(frame: CGRect, isScrollEnable : Bool, titles : [String]) {
  3. self.isScrollEnable = isScrollEnable
  4. self.titles = titles
  5. super.init(frame: frame)
  6. }

设置UI界面

  • 设置UI界面

    • 添加UIScrollView,如果标题过多,则可以滚动
    • 初始化所有的Label,用于显示标题。并且给label添加监听手势
    • 添加顶部线和滑块的View
       
  1. private lazy var scrollView : UIScrollView = {
  2. let scrollView = UIScrollView(frame: self.bounds)
  3. scrollView.showsHorizontalScrollIndicator = false
  4. scrollView.scrollsToTop = false
  5. scrollView.bounces = false
  6. return scrollView
  7. }()
  8. private lazy var scrollLine : UIView = {
  9. let scrollLine = UIView()
  10. scrollLine.backgroundColor = kSelectTitleColor
  11. return scrollLine
  12. }()
  13. private func setupUI() {
  14. // 1.添加scrollView
  15. addSubview(scrollView)
  16. // 2.初始化labels
  17. setupTitleLabels()
  18. // 3.添加定义的线段和滑动的滑块
  19. setupBottomlineAndScrollline()
  20. }
  21. private func setupTitleLabels() {
  22. let titleY : CGFloat = 0
  23. let titleH : CGFloat = bounds.height - kScrollLineH
  24. let count = titles.count
  25. for (index, title) in titles.enumerate() {
  26. // 1.创建Label
  27. let label = UILabel()
  28. // 2.设置Label的属性
  29. label.text = title
  30. label.tag = index
  31. label.textAlignment = .Center
  32. label.textColor = kNormalTitleColor
  33. label.font = UIFont.systemFontOfSize(16.0)
  34. titleLabels.append(label)
  35. // 3.设置label的frame
  36. var titleW : CGFloat = 0
  37. var titleX : CGFloat = 0
  38. if !isScrollEnable {
  39. titleW = bounds.width / CGFloat(count)
  40. titleX = CGFloat(index) * titleW
  41. } else {
  42. let size = (title as NSString).boundingRectWithSize(CGSizeMake(CGFloat(MAXFLOAT), 0), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName : label.font], context: nil)
  43. titleW = size.width
  44. if index != 0 {
  45. titleX = CGRectGetMaxX(titleLabels[index - 1].frame) + kTitleMargin
  46. }
  47. }
  48. label.frame = CGRect(x: titleX, y: titleY, width: titleW, height: titleH)
  49. // 4.将Label添加到父控件中
  50. scrollView.addSubview(label)
  51. // 5.监听label的点击
  52. label.userInteractionEnabled = true
  53. let tapGes = UITapGestureRecognizer(target: self, action: #selector(self.titleLabelClick(_:)))
  54. label.addGestureRecognizer(tapGes)
  55. }
  56. }
  57. private func setupBottomlineAndScrollline() {
  58. // 1.添加bottomline
  59. let bottomline = UIView()
  60. bottomline.frame = CGRect(x: 0, y: bounds.height - 0.5, width: bounds.width, height: 0.5)
  61. bottomline.backgroundColor = UIColor.lightGrayColor()
  62. addSubview(bottomline)
  63. // 2.设置滑块的view
  64. addSubview(scrollLine)
  65. guard let firstLabel = titleLabels.first else { return }
  66. let lineX = firstLabel.frame.origin.x
  67. let lineY = bounds.height - kScrollLineH
  68. let lineW = firstLabel.frame.width
  69. let lineH = kScrollLineH
  70. scrollLine.frame = CGRect(x: lineX, y: lineY, width: lineW, height: lineH)
  71. firstLabel.textColor = kSelectTitleColor
  72. }

封装顶部的PageCotentView

封装构造函数

  • 封装构造函数,让别人在创建对象时,就传入其实需要显示的内容

    • 所有用于显示在UICollectionView的Cell的所有控制器
    • 控制器的父控制器
       
  1. // MARK:- 构造函数
  2. init(frame: CGRect, childVcs : [UIViewController], parentViewController : UIViewController) {
  3. self.childVcs = childVcs
  4. self.parentViewController = parentViewController
  5. super.init(frame: frame)
  6. }

设置UI界面内容

  • 设置UI界面

    • 将所有的子控制器添加到父控制器中
    • 添加UICollectionView,用于展示内容
       
  1. // MARK:- 懒加载属性
  2. private lazy var collectionView : UICollectionView = {
  3. // 1.创建布局
  4. let layout = UICollectionViewFlowLayout()
  5. layout.itemSize = self.bounds.size
  6. layout.minimumLineSpacing = 0
  7. layout.minimumInteritemSpacing = 0
  8. layout.scrollDirection = .Horizontal
  9. // 2.创建collectionView
  10. let collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: layout)
  11. collectionView.showsHorizontalScrollIndicator = false
  12. collectionView.pagingEnabled = true
  13. collectionView.bounces = false
  14. collectionView.scrollsToTop = false
  15. collectionView.dataSource = self
  16. collectionView.delegate = self
  17. collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: kContentCellID)
  18. return collectionView
  19. }()
  20. private func setupUI() {
  21. // 1.添加所有的控制器
  22. for childVc in childVcs {
  23. parentViewController?.addChildViewController(childVc)
  24. }
  25. // 2.添加collectionView
  26. addSubview(collectionView)
  27. }

实现UICollectionView的数据源方法

  • 在返回Cell的方法中,先将cell的contentView中的子控件都移除,防止循环引用造成问题
  • 取出indexPath.item对应的控制器,将控制器的View添加到Cell的contentView中
       
  1. // MARK:- 遵守UICollectionView的数据源
  2. extension PageContentView : UICollectionViewDataSource {
  3. func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  4. return childVcs.count
  5. }
  6. func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  7. let cell = collectionView.dequeueReusableCellWithReuseIdentifier(kContentCellID, forIndexPath: indexPath)
  8. // 移除之前的
  9. for subview in cell.contentView.subviews {
  10. subview.removeFromSuperview()
  11. }
  12. // 取出控制器
  13. let childVc = childVcs[indexPath.item]
  14. childVc.view.frame = cell.contentView.bounds
  15. cell.contentView.addSubview(childVc.view)
  16. return cell
  17. }
  18. }

PageTitleView点击改变PageContentView

  • 通过代理将PageTitleView的事件传递出去
       
  1. /// 定义协议
  2. protocol PageTitleViewDelegate : class {
  3. func pageTitleView(pageTitleView : PageTitleView, didSelectedIndex index : Int)
  4. }
  5. @objc private func titleLabelClick(tapGes : UITapGestureRecognizer) {
  6. // 1.获取点击的下标志
  7. guard let view = tapGes.view else { return }
  8. let index = view.tag
  9. // 2.滚到正确的位置
  10. scrollToIndex(index)
  11. // 3.通知代理
  12. delegate?.pageTitleView(self, didSelectedIndex: index)
  13. }
  • 内部调整
       
  1. // 内容滚动
  2. private func scrollToIndex(index : Int) {
  3. // 1.获取最新的label和之前的label
  4. let newLabel = titleLabels[index]
  5. let oldLabel = titleLabels[currentIndex]
  6. // 2.设置label的颜色
  7. newLabel.textColor = kSelectTitleColor
  8. oldLabel.textColor = kNormalTitleColor
  9. // 3.scrollLine滚到正确的位置
  10. let scrollLineEndX = scrollLine.frame.width * CGFloat(index)
  11. UIView.animateWithDuration(0.15) {
  12. self.scrollLine.frame.origin.x = scrollLineEndX
  13. }
  14. // 4.记录index
  15. currentIndex = index
  16. }
  • 在PageContentView中设置当前应该滚动的位置
       
  1. // MARK:- 对外暴露方法
  2. extension PageContentView {
  3. func scrollToIndex(index : Int) {
  4. let offset = CGPoint(x: CGFloat(index) * collectionView.bounds.width, y: 0)
  5. collectionView.setContentOffset(offset, animated: false)
  6. }
  7. }

PageContentView滚动调整PageTitleView

  • 首先在scrollViewDidScroll的代理方法中就可以监听滚动
  • 那么滚动时,我们有哪些内容是需要传递出去呢?
    • 1> 原来位置的Title颜色会逐渐变暗
    • 2> 目标位置的Title颜色会逐渐变亮
    • 3> 变化程度是和滚动的多少相关
  • 由此得出结论:
    • 我们一共需要获取三个值,并且将这三个值传递出去
    • 1> 起始位置下标值
    • 2> 目标位置下标值
    • 3> 当前滚动的进度
  • 图例分析(缺)
    • 左右滑动时,下标值、进度是不同的
    • 需要经过判断来获取,并且下标值需要防止越界问题
    • 注意:当左滑结束时,此时再+1会出错。因此必须加上targetIndex = sourceIndex,且进度为1
  • 实现代码
       
  1. extension PageContentView : UICollectionViewDelegate {
  2. func scrollViewWillBeginDragging(scrollView: UIScrollView) {
  3. startOffsetX = scrollView.contentOffset.x
  4. }
  5. func scrollViewDidScroll(scrollView: UIScrollView) {
  6. // 1.定义要获取的内容
  7. var sourceIndex = 0
  8. var targetIndex = 0
  9. var progress : CGFloat = 0
  10. // 2.获取进度
  11. let offsetX = scrollView.contentOffset.x
  12. let ratio = offsetX / scrollView.bounds.width
  13. progress = ratio - floor(ratio)
  14. // 3.判断滑动的方向
  15. if offsetX > startOffsetX { // 向左滑动
  16. sourceIndex = Int(offsetX / scrollView.bounds.width)
  17. targetIndex = sourceIndex + 1
  18. if targetIndex >= childVcs.count {
  19. targetIndex = childVcs.count - 1
  20. }
  21. if offsetX - startOffsetX == scrollView.bounds.width {
  22. progress = 1.0
  23. targetIndex = sourceIndex
  24. }
  25. } else { // 向右滑动
  26. targetIndex = Int(offsetX / scrollView.bounds.width)
  27. sourceIndex = targetIndex + 1
  28. if sourceIndex >= childVcs.count {
  29. sourceIndex = childVcs.count - 1
  30. }
  31. progress = 1 - progress
  32. }
  33. // 4.通知代理
  34. delegate?.pageContentView(self, sourceIndex: sourceIndex, targetIndex: targetIndex, progress: progress)
  35. }
  36. }
  • 根据滚动传入的值,调整PageTitleView
  • 两种颜色必须使用RGB值设置(方便通过RGB实现渐变效果)
       
  1. private let kNormalRGB : (CGFloat, CGFloat, CGFloat) = (85, 85, 85)
  2. private let kSelectRGB : (CGFloat, CGFloat, CGFloat) = (255, 128, 0)
  3. private let kDeltaRGB = (kSelectRGB.0 - kNormalRGB.0, kSelectRGB.1 - kNormalRGB.1, kSelectRGB.2 - kNormalRGB.2)
  4. private let kNormalTitleColor = UIColor(red: 85/255.0, green: 85/255.0, blue: 85/255.0, alpha: 1.0)
  5. private let kSelectTitleColor = UIColor(red: 255.0/255.0, green: 128/255.0, blue: 0/255.0, alpha: 1.0)
  • 调整scrollLine&两个Label颜色渐变
       
  1. // MARK:- 对外暴露方法
  2. extension PageTitleView {
  3. func setCurrentTitle(sourceIndex : Int, targetIndex : Int, progress : CGFloat) {
  4. // 1.取出两个Label
  5. let sourceLabel = titleLabels[sourceIndex]
  6. let targetLabel = titleLabels[targetIndex]
  7. // 2.移动scrollLine
  8. let moveMargin = targetLabel.frame.origin.x - sourceLabel.frame.origin.x
  9. scrollLine.frame.origin.x = sourceLabel.frame.origin.x + moveMargin * progress
  10. // 3.颜色渐变
  11. sourceLabel.textColor = UIColor(red: (kSelectRGB.0 - kDeltaRGB.0 * progress) / 255.0, green: (kSelectRGB.1 - kDeltaRGB.1 * progress) / 255.0, blue: (kSelectRGB.2 - kDeltaRGB.2 * progress) / 255.0, alpha: 1.0)
  12. targetLabel.textColor = UIColor(red: (kNormalRGB.0 + kDeltaRGB.0 * progress)/255.0, green: (kNormalRGB.1 + kDeltaRGB.1 * progress)/255.0, blue: (kNormalRGB.2 + kDeltaRGB.2 * progress)/255.0, alpha: 1.0)
  13. }
  14. }

来源:http://bbs.520it.com/forum.php?mod=viewthread&tid=2246

小码哥-玩转【斗鱼直播APP】系列之首页布局分析实现相关推荐

  1. 小码哥-玩转【斗鱼直播APP】系列之项目部署

    项目部署目的 任何一个项目最好使用源代码管理工具 源代码管理工具可以帮助我们解决备份.版本回退等等问题 因为是非基础篇,因此具体好处不在累述 常见的源代码管理工具: SVN: 集中式源代码管理工具 G ...

  2. 小码哥-玩转【斗鱼直播APP】系列之获取APP图片资源

    重要提醒 原作者的代码有少许问题, 可能会崩溃 我已经在我fork的代码中修复了问题. 请大家去我的Github上下载该工具. 如果对你有帮助, 可以star一下哈. Github地址: coderw ...

  3. 小码哥-玩转【斗鱼直播APP】系列之利用青花瓷抓取数据

    利用青花瓷抓取数据 青花瓷是什么? 当然这里可不是周董的歌曲, 而是我们用于抓取接口的工具. 安装一下这个软件 百度搜索该工具会找到很多绿色版(破解版的文艺说法). 安装即可, 不再累述. 手机端配置 ...

  4. 小码哥-玩转【斗鱼直播APP】系列之首页导航栏设置

    首页导航栏设置 重点掌握内容 导航栏添加Items 给系统的类扩充方法 扩充便利构造函数 效果展示 在iOS开发中,导航栏的设置是必不可少的一部分. 通常导航栏中会放很多的UIBarButtonIte ...

  5. 小码哥-玩转【斗鱼直播APP】系列之实现无限轮播

    实现无限轮播 生活杂谈 最近很多童鞋私信我,Swift项目有些语法跟不上.希望我出OC版的(OC版我会在后续推出),但是以我的考虑来说,Swift在语言排行版上面其实已经超过OC,另外国内现在新项目一 ...

  6. 小码哥-玩转【斗鱼直播APP】系列之框架搭建

    搭建效果展示 框架搭建分析 首先最底部是一个UITabbar,因此我们可以用一个UITabBarController作为启动控制器 分别添加子控制器HomeVc.LiveVc.FollowVc.Pro ...

  7. 小码哥-玩转【斗鱼直播APP】系列之布局推荐界面

    布局推荐界面 实现效果 今天内容完成效果 推荐界面分析 上层有无限轮播器(之后再完成) 滚动的UIScrollView或者UICollectionView(之后再完成) 下面是UICollection ...

  8. 小码哥-玩转【斗鱼直播APP】系列之项目基本设置

    设置的内容 任何一个项目在新建之后都有很多东西需要进行设置. 比如版本号.BundleID.部署版本等等 设置BundleID.部署版本.横竖屏等 设置图标.启动图片 设置项目名称 Info.plis ...

  9. 小码哥-玩转【斗鱼直播APP】系列之游戏推荐展示

    游戏推荐展示 展示效果 展示效果 思路分析 其实这个实现比较简单,也是有两种方案 UIScrollView:直接在上面放上UIButton即可 UICollectionView:每一个游戏用一个Cel ...

最新文章

  1. 前端解决跨域问题的8种方案(最新最全)
  2. 阿里巴巴开源的 Blink 实时计算框架真香
  3. Linux 段错误详解
  4. IromPython .Net 的简介和第一个例子
  5. SolrException: Index locked 和 Error opening new searcher 最终解决方案(找了好久才解决)
  6. Linux 压缩与解压
  7. matlab生成随机粗糙表面_随机粗糙面建模
  8. java的dom4j怎么调_dom4j.jar 的调试方法
  9. Tipard Screen Capture for Mac如何掌握音频?速来看
  10. Opengl1.1绘图之GL_COLOR_LOGIC_OP
  11. 查看Jetson系列产品JetPack的版本信息
  12. 极品抓鸡36课------8080端口入侵笔记
  13. android 小游戏心得、,滴答滴答:双人故事
  14. 谷歌浏览器使用charles抓包localhost
  15. Gmail(以及Google其他服务)的可用IPV6地址【2013年01月12日测试可用】
  16. word强调文字颜色在哪,强调文字颜色2 word2010如何将文字设置成红色,强调文
  17. 40+个工业检测数据集
  18. Iphone开发用导航控制器实现视图的分层切换(UINavigationController)
  19. C语言:小写字母与大写字母的转换
  20. 【产品设计】用户画像模板

热门文章

  1. springBoot启动异常【Consider defining a bean of type】解决
  2. 关于柱塞泵R9.8-9.8-9.8-9.8
  3. [附源码]计算机毕业设计JAVAjsp高校班主任班级管理系统
  4. 自学整理的软件测试常见的面试题
  5. C语言程序——数组(1)
  6. 【闪电侠学netty】第5章 客户端启动流程
  7. kafka创建Topic出现的问题
  8. 并行计算与分布式处理的区别?
  9. java-net-php-python-springboot社区志愿者管理系统计算机毕业设计程序
  10. SQLException: Value ‘0000-00-00 00:00:00‘ can not be represented as java.sql.Timestamp