嵌套scrollview, 实现tab吸顶,页面左右滑动切换,上滑tab吸顶,自己研究了一下,下面看看效果
创建一些基本UI
/// 屏幕宽度
let Screen_Width = UIScreen.main.bounds.width
/// 屏幕高度
let Screen_Height = UIScreen.main.bounds.height
class JWDoubleScrollViewVC: UIViewController {
var headView:UIView?
var slideLine:UILabel?
var segBtns = [UIButton]()
var tableviews = [UITableView]()
let segWidth = Screen_Width / 4
let headViewH = 300
let segH = 40
var currentTabIndex = 0
var distance:Int{
get{
return headViewH - segH
}
}
fileprivate var rootScrollView:MyScrollView={
let scrollview = MyScrollView.init()
scrollview.backgroundColor = UIColor.white
scrollview.bounces = false
scrollview.showsVerticalScrollIndicator = false
scrollview.showsHorizontalScrollIndicator = false
return scrollview
}()
fileprivate var containerScrollView:UIScrollView = {
let scrollview = UIScrollView.init()
scrollview.backgroundColor = UIColor.white
scrollview.bounces = false
scrollview.isPagingEnabled = true
scrollview.showsVerticalScrollIndicator = false
scrollview.showsHorizontalScrollIndicator = false
return scrollview
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.white
self.setupUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
rootScrollView.isScrollEnabled = true
}
func setupUI() {
rootScrollView.delegate = self
containerScrollView.delegate = self
let rootView = UIView.init()
self.view.addSubview(rootView)
rootView.snp.makeConstraints { (make) in
make.top.equalTo(90)
make.left.right.bottom.equalToSuperview()
}
rootView.layoutIfNeeded()
rootView.addSubview(rootScrollView)
rootScrollView.snp.makeConstraints { (make) in
make.edges.equalTo(rootView)
}
rootScrollView.layoutIfNeeded()
//headview
headView = UIView.init()
headView?.backgroundColor = UIColor.blue
rootScrollView.addSubview(headView!)
headView?.snp.makeConstraints({ (make) in
make.top.left.right.equalToSuperview()
make.width.equalTo(Screen_Width)
make.height.equalTo(headViewH)
})
headView?.layoutIfNeeded()
rootScrollView.addSubview(containerScrollView)
containerScrollView.snp.makeConstraints { (make) in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(headView!.snp.bottom)
make.width.equalTo(Screen_Width)
make.height.equalTo(rootScrollView.frame.height)
}
containerScrollView.layoutIfNeeded()
//tab背景view
let btnContainerView = UIView.init()
rootScrollView.addSubview(btnContainerView)
btnContainerView.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.height.equalTo(segH)
make.bottom.equalTo(headView!.snp.bottom)
make.width.equalTo(Screen_Width)
}
btnContainerView.layoutIfNeeded()
for i in 0...3 {
//添加Tab
let button = self.createButton(i)
btnContainerView.addSubview(button)
segBtns.append(button)
//添加tableview
let tableview = self.createTableView(i)
containerScrollView.addSubview(tableview)
tableviews.append(tableview)
}
//tab底部横线
slideLine = UILabel.init(frame: CGRect.init(x: 0, y: CGFloat(segH - 6), width: segWidth, height: 4))
slideLine?.backgroundColor = .white
slideLine?.layer.cornerRadius = 4/2
slideLine?.layer.masksToBounds = true
btnContainerView.addSubview(slideLine!)
//设置scrollview滑动区域
containerScrollView.contentSize = CGSize.init(width: CGFloat(segBtns.count) * Screen_Width, height: 0)
}
/**
创建Tab
*/
func createButton(_ i:Int) -> UIButton {
let button = UIButton.init(type: .custom)
button.frame = CGRect.init(x: CGFloat(i)*segWidth, y: 0, width: segWidth, height: CGFloat(segH))
button.setTitle(String.init(format: "第%i个", i), for: .normal)
button.titleLabel?.textAlignment = .center
button.tag = 1000 + i
button.backgroundColor = .red
button.setTitleColor(UIColor.white, for: .normal)
button.setTitleColor(UIColor.yellow, for: .selected)
button.addTarget(self, action: #selector(segAction(button:)), for:.touchUpInside)
return button
}
/**
创建tableview
*/
func createTableView(_ i:Int) ->UITableView{
let tableView = UITableView.init(frame: .zero, style: .plain)
tableView.frame = CGRect.init(x: CGFloat(i)*Screen_Width, y: 0, width: Screen_Width, height: rootScrollView.frame.height - CGFloat(segH))
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = .green
tableView.sectionHeaderHeight = 0
tableView.sectionFooterHeight = 0
//tableView.bounces = false
tableView.backgroundColor = UIColor.white
tableView.register(UITableViewCell.classForCoder(), forCellReuseIdentifier: NSStringFromClass(UITableViewCell.classForCoder()))
return tableView
}
/**
滑动tab切换
*/
func sliderAnimationWithTag(tag:Int){
rootScrollView.isScrollEnabled = true
currentTabIndex = tag;
for item in segBtns.enumerated() {
let button = item.element
button.isSelected = false
}
let button = segBtns[tag]
button.isSelected = true
UIView.animate(withDuration: 0.25) { [weak self] in
self!.slideLine?.center = CGPoint.init(x: CGFloat(button.center.x), y: CGFloat((self!.slideLine?.center.y)!))
}
}
@objc func segAction(button:UIButton) {
//滑动到指定页面
containerScrollView.setContentOffset(CGPoint.init(x:CGFloat(button.tag - 1000) * Screen_Width, y: 0), animated: true)
}
//tablview是否可以滑动
func canTableViewScroll() -> Bool {
return rootScrollView.contentOffset.y >= CGFloat(self.distance)
}
//主rootscrollview是否可以滑动
func canRootViewScroll() -> Bool {
return tableviews[currentTabIndex].contentOffset.y <= 0
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
此部分处理嵌套scrollview手势页面交互
extension JWDoubleScrollViewVC:UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.isKind(of: UITableView.classForCoder()){ //tableview
let offY = tableviews[currentTabIndex].contentOffset.y;
if offY < 0 {
tableviews[currentTabIndex].contentOffset = .zero;//去掉tableview上方弹性
}
guard !canTableViewScroll() else {
return
}
scrollView.contentOffset.y = 0
}else if scrollView === rootScrollView{ //主scrollview
guard !canRootViewScroll() else {
return
}
let sliderSafeArea = (self.distance);
scrollView.setContentOffset(CGPoint.init(x: 0, y: sliderSafeArea), animated: false)
}else if scrollView === containerScrollView{ //滑动scrollview
rootScrollView.isScrollEnabled = false
//滑动切换Tab
let page = Double(scrollView.contentOffset.x/Screen_Width)
self.sliderAnimationWithTag(tag: Int(page + 0.5))
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
rootScrollView.isScrollEnabled = true
}
}
extension JWDoubleScrollViewVC:UITableViewDelegate,UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50.0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 30
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tableviewcell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(UITableViewCell.classForCoder()), for: indexPath)
tableviewcell.textLabel?.text = String.init(format: "第%i个", indexPath.row)
tableviewcell.backgroundColor = .orange
return tableviewcell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
}
}
class MyScrollView:UIScrollView,UIGestureRecognizerDelegate{
//当前scrollview与其他scrollview都响应手势操作
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
demo 地址:jwsource/JSDoubleScrollView