实现淘宝商品页面的滑块浮动切换页面的效果修改版
2016-04-25 10:44
567 查看
前言, 之前写了一篇文章, 实现类似淘宝商品界面的滑块效果, 不过很(##抱歉##)的是, 笔者当时没有测试TableView等的使用,大家反映TableView不能正常使用,(研究一段时间发现, 之前的做法不适结合合TableView使用) 这里就整理了下重新实现了, 比之前的确实要麻烦一点, 如果在你的项目中不需要结合TableView就可以简单的按照之前的方法实现.
最终效果
注意!!! 实现这个效果github上的代码有更新, 大家使用最新的代码
更新说明: 使每个页面在顶端滚动的偏移量不相互影响
构思: 利用监控和设置UIScrollView的偏移量来实现
.
层级结构, 第一层为控制器的view, 第二层为contentView, 第三层为 headView和segmentView
第二层的contentView,设置contentView的大小和控制器的view的大小一样, 来显示子控制器的view的内容, 需要设置他的子控制器view的tableView(collectionVie)的初始偏移量为segmentView和headView的高度之和,同时将segmentView和headView添加到view上面, 以实现tableView在滚动的时候segmentView和headView可以同步滚动
subview的添加顺序, 先添加contentView, 然后再添加segmentView和headView(因为contentView和view大小一样, 若是在后面添加就将segmentView和headView遮住了)
同步滚动原理: 监控子控制器的scrollView的滚动偏移量(contentOffset.y), 根据偏移量的改变量来同步的调整segmentView和headView的frame, 这里的监控之前我是使用Closure来实现,但是后面需要更新tableView的偏移量有需要一个Closure, 所以就改为了delegate来实现.
使segmentView浮动: 通过监控子控制器的scrollView的滚动偏移量(contentOffset.y), 根据偏移量的改变量来同步的调整segmentView和headView的frame, 当segmentView同步”滚动”到顶部的时候, 通过判断scrollView的滚动偏移量的范围来固定segmentView和headView的frame, 即达到浮动效果
在segmentView和headView的frame随着scrollView滚动到下方原始位置的时候, 通过判断scrollView的滚动偏移量的范围来固定segmentView和headView的frame,
实现部分 , 代码量不大
1 属性部分, 这些懒加载方法里面设置了他们的相关属性, 其中的具体设置和动手写一个快速集成网易新闻,腾讯视频,头条首页的ScrollPageView,显示滚动视图这里面介绍的使用相同, 这里就不在赘述了注意设置这些控件的frame的时候使用到了一些常量, 请根据您项目的具体需要改变
设置部分
override func viewDidLoad() { super.viewDidLoad() title = "简书个人主页" // 这个是必要的设置, 如果没有设置导致显示内容不正常, 请尝试设置这个属性 automaticallyAdjustsScrollViewInsets = false //1. 添加子控制器为PageTableViewController或者继承自他的Controller, // 或者你可以参考PageTableViewController他里面的实现自行实现(可以使用UICollectionView)相关的代理和属性 并且设置delegate为self addChildVcs() // 2. 先添加contentView view.addSubview(contentView) // 3. 再添加headView view.addSubview(headView) // 4. 再添加topView view.addSubview(topView) // 添加子控制器的时候需要设置代理 func addChildVcs() { let vc1 = PageTableViewController() vc1.delegate = self addChildViewController(vc1) let vc2 = Test1Controller() vc2.delegate = self addChildViewController(vc2) }
子控制器的代理方法实现部分
// MARK:- PageTableViewDelegate - 监控子控制器中的tableview的滚动和更新相关的UI extension Vc8Controller: PageTableViewDelegate { // 设置将要显示的tableview的contentOffset.y func setupTableViewOffSetYWhenViewWillAppear(scrollView: UIScrollView) { // 当子控制器的tableview向上滚动很多的时候, 重新设置offY if offSetY > -(naviBarHeight + segmentViewHeight) { offSetY = -(naviBarHeight + segmentViewHeight) } print("\\\\(offSetY)--------------") scrollView.contentOffset.y = offSetY } // 根据子控制器的scrolView的偏移量来调整UI func scrollViewIsScrolling(scrollView: UIScrollView) { let deltaY = scrollView.contentOffset.y - offSetY offSetY = scrollView.contentOffset.y // print(offSetY) if offSetY > -(defaultOffSetY - headViewHeight) { // 使滑块停在navigationBar下面 headView.frame.origin.y = naviBarHeight - headViewHeight topView.frame.origin.y = naviBarHeight return } else if offSetY < -defaultOffSetY { // 使headView停在navigationBar下面 headView.frame.origin.y = naviBarHeight topView.frame.origin.y = naviBarHeight + headViewHeight return } // 这里是让滑块和headView随着上下滚动 headView.frame.origin.y -= deltaY topView.frame.origin.y -= deltaY } }
contentView的代理方法实现
// MARK:- ContentViewDelegate extension Vc8Controller: ContentViewDelegate { var segmentView: ScrollSegmentView { return topView } }
子控制器部分, 这里比较简单, 只需要实现scrollView的滚动代理方法, 在里面通过代理调用子控制器的代理方法, 通知给父控制器, 然后是在viewWillAppear()的方法中通过代理更新tableView(collectioVew)的contentOffset
注意 /// !!! 不要在viewDidLoad()方法里面设置tableView或者collectionView的偏移量, 在初始化方法中设置偏移量,否则可能导致显示不正常
// 协议方法// MARK: PageTableViewDelegate protocol PageTableViewDelegate: class { func scrollViewIsScrolling(scrollView: UIScrollView) func setupTableViewOffSetYWhenViewWillAppear(scrollView: UIScrollView) }
初始化
func setupTableView() { tableView = UITableView(frame: self.view.bounds, style: .Plain) tableView.delegate = self tableView.dataSource = self // 设置tableview的内容偏移量 tableView.contentInset = UIEdgeInsets(top: defaultOffSetY, left: 0, bottom: 0, right: 0) self.view.addSubview(tableView) } /// !!! 不要在viewDidLoad()方法里面设置tableView或者collectionView的偏移量, 在初始化方法中设置偏移量,否则可能导致显示不正常 init() { super.init(nibName: nil, bundle: nil) setupTableView() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
viewWillAppear
override func viewWillAppear(animated: Bool) { super.viewWillAppear(true) // 通知父控制器重新设置tableView的contentOffset.y delegate?.setupTableViewOffSetYWhenViewWillAppear(tableView) // print(tableView.contentOffset.y) }
UIScrollViewDelegate
// MARK: UIScrollViewDelegate - 监控tableview的滚动, 将改变通知给通知父控制器 extension PageTableViewController: UIScrollViewDelegate { func scrollViewDidScroll(scrollView: UIScrollView) { delegate?.scrollViewIsScrolling(scrollView) } }
>源码地址,已更新, 如果您觉得有帮助,不妨给个star鼓励一下,欢迎关注, 欢迎交流
相关文章推荐
- Android之使用Http协议实现文件上传功能
- Android Native 绘图方法
- mysql集群之MMM简单搭建
- 通晓网络测试常用命令
- 脚本之家完全改版完毕
- C#中struct和class的区别详解
- VBS ArrayList Class vbs中的数组类
- 大家看了就明白了css样式中类class与标识id选择符的区别小结
- Nodejs学习笔记之测试驱动
- winform异型不规则界面设计的实现方法
- 深入了解PHP类Class的概念
- jquery 表单验证之通过 class验证表单不为空
- setAttribute 与 class冲突解决
- JavaScript中的类(Class)详细介绍
- javascript面向对象包装类Class封装类库剖析
- 详解js中class的多种函数封装方法
- jQuery使用hide方法隐藏指定元素class样式用法实例
- jQuery给多个不同元素添加class样式的方法
- jQuery点击改变class并toggle及toggleClass()方法定义用法
- jquery采用oop模式class类的使用示例