- 基础版实现思路
1.1 层次结构
底部是一个UITableView,上面黄色部分为tableView的tableHeaderView,cell的数 量为1,cell的contentView上放置了一个LTPageView, pageView上放置了一个scrollView且可以左右滑动分页,scrollView上放置控制器view,控制器view上放置各自的scrollView(tableView或collectionView)
1.2 使用方法
a.创建LTSimpleMabager,并添加到视图,传入frame,子控制器数组,标题数组,当前的控制器以及pageView的样式设置
LTSimpleManager(frame: <#T##CGRect#>, viewControllers: <#T##[UIViewController]#>, titles: <#T##[String]#>, currentViewController: <#T##UIViewController#>, layout: <#T##LTLayout#>)
b.初始化子控制器的scrollView(tableView或collectionView),且tableView的y值从pageTitleView的高度开始,Demo中为44,具体可根据产品需求而定,tableView的height则为父view的高减去44
c.将子控制器的scrollView(tableView或collectionView)赋值给glt_scollView即glt_scrollView = tableView,以下会说明原因。
1.3 实现思路
a.当滑动底部tableView的时候,当tableView的contentOffset.y 小于 header的高的时候,将内容ScrollView的contentOffset设置为.zero
private func contentScrollViewScrollConfig(_ viewController: UIViewController) { viewController.glt_scrollView?.scrollHandle = {[weak self] scrollView in guard let `self` = self else { return } self.contentTableView = scrollView if self.tableView.contentOffset.y < self.kHeaderHeight { scrollView.contentOffset = .zero; scrollView.showsVerticalScrollIndicator = false }else{ scrollView.showsVerticalScrollIndicator = true } } }
b.当滑动内容ScrollView的时候, 当内容contentOffset.y 大于 0(说明滑动的是内容ScrollView) 或者 当底部tableview的contentOffset.y大于 header的高度的时候,将底部tableView的偏移量设置为kHeaderHeight, 并将其他的scrollView的contentOffset置为.zero
public func scrollViewDidScroll(_ scrollView: UIScrollView) { guard scrollView == tableView, let contentTableView = contentTableView else { return } let offsetY = scrollView.contentOffset.y if contentTableView.contentOffset.y > 0.0 || offsetY > kHeaderHeight { tableView.contentOffset = CGPoint(x: 0.0, y: kHeaderHeight) } if scrollView.contentOffset.y < kHeaderHeight { for viewController in viewControllers { guard viewController.glt_scrollView != scrollView else { continue } viewController.glt_scrollView?.contentOffset = .zero } } }
c.headerView添加以及各个点击事件回调处理
simpleManager.configHeaderView {[weak self] in guard let strongSelf = self else { return nil } let headerView = strongSelf.testLabel() return headerView }
simpleManager.didSelectIndexHandle { (index) in }
simpleManager.refreshTableViewHandle { (scrollView, index) in scrollView.mj_header = MJRefreshNormalHeader { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: { scrollView.mj_header.endRefreshing() }) } }
- 进阶版实现思路
2.1 层次结构
底部是LTPageView, pageView上放置了一个scrollView且可以左右滑动分页,scrollView上放置控制器view,headerView是一个单独的View在顶部,利用scrollView的contentInset将其放置在了最上面
2.2 使用方法
a.创建LTAdvancedManager,并添加到视图,传入frame,子控制器数组,标题数组,当前的控制器以及pageView的样式设置和自己的headerView(在闭包中返回即可)
LTAdvancedManager(frame: <#T##CGRect#>, viewControllers: <#T##[UIViewController]#>, titles: <#T##[String]#>, currentViewController: <#T##UIViewController#>, layout: <#T##LTLayout#>, headerViewHandle: <#T##() -> UIView#>)
b.初始化子控制器的scrollView(tableView或collectionView),且tableView的y值从0开始,tableView的height则为父view的高减去44
c.将子控制器的的scrollView(tableView或collectionView)赋值给glt_scollView即glt_scrollView = tableView,以下会说明原因
2.3 实现思路
主要是利用子控制的滚动来控制headerView
//MARK: 当前控制器的滑动方法事件处理 private func contentScrollViewDidScroll(_ contentScrollView: UIScrollView, _ absOffset: CGFloat) { //获取当前控制器 let currentVc = viewControllers[currentSelectIndex] //外部监听当前ScrollView的偏移量 self.delegate?.glt_scrollViewOffsetY?((currentVc.glt_scrollView?.contentOffset.y ?? kHeaderHeight) + self.kHeaderHeight + layout.sliderHeight) //获取偏移量 let offsetY = contentScrollView.contentOffset.y //获取当前pageTitleView的Y值 var pageTitleViewY = pageView.pageTitleView.frame.origin.y //pageTitleView从初始位置上升的距离 let titleViewBottomDistance = offsetY + kHeaderHeight + layout.sliderHeight let headerViewOffset = titleViewBottomDistance + pageTitleViewY if absOffset > 0 && titleViewBottomDistance > 0 {//向上滑动 if headerViewOffset >= kHeaderHeight { pageTitleViewY += -absOffset if pageTitleViewY <= hoverY { pageTitleViewY = hoverY } } }else{//向下滑动 if headerViewOffset < kHeaderHeight { pageTitleViewY = -titleViewBottomDistance + kHeaderHeight if pageTitleViewY >= kHeaderHeight { pageTitleViewY = kHeaderHeight } } } pageView.pageTitleView.frame.origin.y = pageTitleViewY headerView?.frame.origin.y = pageTitleViewY - kHeaderHeight let lastDiffTitleToNavOffset = pageTitleViewY - lastDiffTitleToNav lastDiffTitleToNav = pageTitleViewY //使其他控制器跟随改变 for subVC in viewControllers { guard subVC != currentVc else { continue } guard let vcGlt_scrollView = subVC.glt_scrollView else { continue } vcGlt_scrollView.contentOffset.y += (-lastDiffTitleToNavOffset) subVC.glt_upOffset = String(describing: vcGlt_scrollView.contentOffset.y) } }
源码:https://github.com/gltwy/LTScrollView
- 基础版实现思路
1.1 层次结构
底部是一个UITableView,上面黄色部分为tableView的tableHeaderView,cell的数 量为1,cell的contentView上放置了一个LTPageView, pageView上放置了一个scrollView且可以左右滑动分页,scrollView上放置控制器view,控制器view上放置各自的scrollView(tableView或collectionView)
1.2 使用方法
a.创建LTSimpleMabager,并添加到视图,传入frame,子控制器数组,标题数组,当前的控制器以及pageView的样式设置
LTSimpleManager(frame: <#T##CGRect#>, viewControllers: <#T##[UIViewController]#>, titles: <#T##[String]#>, currentViewController: <#T##UIViewController#>, layout: <#T##LTLayout#>)
b.初始化子控制器的scrollView(tableView或collectionView),且tableView的y值从pageTitleView的高度开始,Demo中为44,具体可根据产品需求而定,tableView的height则为父view的高减去44
c.将子控制器的scrollView(tableView或collectionView)赋值给glt_scollView即glt_scrollView = tableView,以下会说明原因。
1.3 实现思路
a.当滑动底部tableView的时候,当tableView的contentOffset.y 小于 header的高的时候,将内容ScrollView的contentOffset设置为.zero
private func contentScrollViewScrollConfig(_ viewController: UIViewController) { viewController.glt_scrollView?.scrollHandle = {[weak self] scrollView in guard let `self` = self else { return } self.contentTableView = scrollView if self.tableView.contentOffset.y < self.kHeaderHeight { scrollView.contentOffset = .zero; scrollView.showsVerticalScrollIndicator = false }else{ scrollView.showsVerticalScrollIndicator = true } } } private func contentScrollViewScrollConfig(_ viewController: UIViewController) { viewController.glt_scrollView?.scrollHandle = {[weak self] scrollView in guard let `self` = self else { return } self.contentTableView = scrollView if self.tableView.contentOffset.y < self.kHeaderHeight { scrollView.contentOffset = .zero; scrollView.showsVerticalScrollIndicator = false }else{ scrollView.showsVerticalScrollIndicator = true } } }
b.当滑动内容ScrollView的时候, 当内容contentOffset.y 大于 0(说明滑动的是内容ScrollView) 或者 当底部tableview的contentOffset.y大于 header的高度的时候,将底部tableView的偏移量设置为kHeaderHeight, 并将其他的scrollView的contentOffset置为.zero
public func scrollViewDidScroll(_ scrollView: UIScrollView) { guard scrollView == tableView, let contentTableView = contentTableView else { return } let offsetY = scrollView.contentOffset.y if contentTableView.contentOffset.y > 0.0 || offsetY > kHeaderHeight { tableView.contentOffset = CGPoint(x: 0.0, y: kHeaderHeight) } if scrollView.contentOffset.y < kHeaderHeight { for viewController in viewControllers { guard viewController.glt_scrollView != scrollView else { continue } viewController.glt_scrollView?.contentOffset = .zero } } } public func scrollViewDidScroll(_ scrollView: UIScrollView) { guard scrollView == tableView, let contentTableView = contentTableView else { return } let offsetY = scrollView.contentOffset.y if contentTableView.contentOffset.y > 0.0 || offsetY > kHeaderHeight { tableView.contentOffset = CGPoint(x: 0.0, y: kHeaderHeight) } if scrollView.contentOffset.y < kHeaderHeight { for viewController in viewControllers { guard viewController.glt_scrollView != scrollView else { continue } viewController.glt_scrollView?.contentOffset = .zero } } }
c.headerView添加以及各个点击事件回调处理
simpleManager.configHeaderView {[weak self] in guard let strongSelf = self else { return nil } let headerView = strongSelf.testLabel() return headerView } simpleManager.configHeaderView {[weak self] in guard let strongSelf = self else { return nil } let headerView = strongSelf.testLabel() return headerView }
simpleManager.didSelectIndexHandle { (index) in } simpleManager.didSelectIndexHandle { (index) in }
simpleManager.refreshTableViewHandle { (scrollView, index) in scrollView.mj_header = MJRefreshNormalHeader { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: { scrollView.mj_header.endRefreshing() }) } }simpleManager.refreshTableViewHandle { (scrollView, index) in scrollView.mj_header = MJRefreshNormalHeader { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: { scrollView.mj_header.endRefreshing() }) } }
- 进阶版实现思路
2.1 层次结构
底部是LTPageView, pageView上放置了一个scrollView且可以左右滑动分页,scrollView上放置控制器view,headerView是一个单独的View在顶部,利用scrollView的contentInset将其放置在了最上面
LTAdvancedManager(frame: <#T##CGRect#>, viewControllers: <#T##[UIViewController]#>, titles: <#T##[String]#>, currentViewController: <#T##UIViewController#>, layout: <#T##LTLayout#>, headerViewHandle: <#T##() -> UIView#>)LTAdvancedManager(frame: <#T##CGRect#>, viewControllers: <#T##[UIViewController]#>, titles: <#T##[String]#>, currentViewController: <#T##UIViewController#>, layout: <#T##LTLayout#>, headerViewHandle: <#T##() -> UIView#>)
2.2 使用方法
a.创建LTAdvancedManager,并添加到视图,传入frame,子控制器数组,标题数组,当前的控制器以及pageView的样式设置和自己的headerView(在闭包中返回即可)
//MARK: 当前控制器的滑动方法事件处理 private func contentScrollViewDidScroll(_ contentScrollView: UIScrollView, _ absOffset: CGFloat) { //获取当前控制器 let currentVc = viewControllers[currentSelectIndex] //外部监听当前ScrollView的偏移量 self.delegate?.glt_scrollViewOffsetY?((currentVc.glt_scrollView?.contentOffset.y ?? kHeaderHeight) + self.kHeaderHeight + layout.sliderHeight) //获取偏移量 let offsetY = contentScrollView.contentOffset.y //获取当前pageTitleView的Y值 var pageTitleViewY = pageView.pageTitleView.frame.origin.y //pageTitleView从初始位置上升的距离 let titleViewBottomDistance = offsetY + kHeaderHeight + layout.sliderHeight let headerViewOffset = titleViewBottomDistance + pageTitleViewY if absOffset > 0 && titleViewBottomDistance > 0 {//向上滑动 if headerViewOffset >= kHeaderHeight { pageTitleViewY += -absOffset if pageTitleViewY <= hoverY { pageTitleViewY = hoverY } } }else{//向下滑动 if headerViewOffset < kHeaderHeight { pageTitleViewY = -titleViewBottomDistance + kHeaderHeight if pageTitleViewY >= kHeaderHeight { pageTitleViewY = kHeaderHeight } } } pageView.pageTitleView.frame.origin.y = pageTitleViewY headerView?.frame.origin.y = pageTitleViewY - kHeaderHeight let lastDiffTitleToNavOffset = pageTitleViewY - lastDiffTitleToNav lastDiffTitleToNav = pageTitleViewY //使其他控制器跟随改变 for subVC in viewControllers { guard subVC != currentVc else { continue } guard let vcGlt_scrollView = subVC.glt_scrollView else { continue } vcGlt_scrollView.contentOffset.y += (-lastDiffTitleToNavOffset) subVC.glt_upOffset = String(describing: vcGlt_scrollView.contentOffset.y) } }
b.初始化子控制器的scrollView(tableView或collectionView),且tableView的y值从0开始,tableView的height则为父view的高减去44
c.将子控制器的的scrollView(tableView或collectionView)赋值给glt_scollView即glt_scrollView = tableView,以下会说明原因
2.3 实现思路
主要是利用子控制的滚动来控制headerView
//MARK: 当前控制器的滑动方法事件处理 private func contentScrollViewDidScroll(_ contentScrollView: UIScrollView, _ absOffset: CGFloat) { //获取当前控制器 let currentVc = viewControllers[currentSelectIndex] //外部监听当前ScrollView的偏移量 self.delegate?.glt_scrollViewOffsetY?((currentVc.glt_scrollView?.contentOffset.y ?? kHeaderHeight) + self.kHeaderHeight + layout.sliderHeight) //获取偏移量 let offsetY = contentScrollView.contentOffset.y //获取当前pageTitleView的Y值 var pageTitleViewY = pageView.pageTitleView.frame.origin.y //pageTitleView从初始位置上升的距离 let titleViewBottomDistance = offsetY + kHeaderHeight + layout.sliderHeight let headerViewOffset = titleViewBottomDistance + pageTitleViewY if absOffset > 0 && titleViewBottomDistance > 0 {//向上滑动 if headerViewOffset >= kHeaderHeight { pageTitleViewY += -absOffset if pageTitleViewY <= hoverY { pageTitleViewY = hoverY } } }else{//向下滑动 if headerViewOffset < kHeaderHeight { pageTitleViewY = -titleViewBottomDistance + kHeaderHeight if pageTitleViewY >= kHeaderHeight { pageTitleViewY = kHeaderHeight } } } pageView.pageTitleView.frame.origin.y = pageTitleViewY headerView?.frame.origin.y = pageTitleViewY - kHeaderHeight let lastDiffTitleToNavOffset = pageTitleViewY - lastDiffTitleToNav lastDiffTitleToNav = pageTitleViewY //使其他控制器跟随改变 for subVC in viewControllers { guard subVC != currentVc else { continue } guard let vcGlt_scrollView = subVC.glt_scrollView else { continue } vcGlt_scrollView.contentOffset.y += (-lastDiffTitleToNavOffset) subVC.glt_upOffset = String(describing: vcGlt_scrollView.contentOffset.y) } }