网络知识 娱乐 iOS 多个TableView嵌套滚动处理

iOS 多个TableView嵌套滚动处理

前言

此次项目中遇到了两类UITableView嵌套使用的场景,里面遇到了一些问题,所以就写此文章记录一下

UITableView 嵌套 UITableView,

首先,设置允许同时识别手势,

class YLGestureTableView: UITableView, UIGestureRecognizerDelegate { 
    open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    } 
}

1、UITableView嵌套,从顶部下拉刷新

通过观察视图需要滑动,来控制视图的Contentoffset.y的移动,来达到效果

1.1 设置父视图

此处继承父视图即可,顶部高度可以自己设置高度,通过通知来改变滑动状态,具体滑动哪个

class UpFatherController: UIViewController {
    
    // MARK: - 1.interface
    ///是否可以滑动
    private var canScroll: Bool = true
    ///顶部高度
    public let upTop: CGFloat = 300
    
    // MARK: - 2.lift cycle
    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(self, selector: #selector(notiScroll), name: NSNotification.Name("up_father"), object: nil)
    }
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    // MARK: - 3.private methods
    ///可以滚动接受
    @objc private func notiScroll() {
        canScroll = true
    }
}

extension UpFatherController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offSetY = scrollView.contentOffset.y
        if canScroll == false {
            scrollView.contentOffset = CGPoint(x: 0, y: upTop)
        }
        if offSetY >= upTop {
            canScroll = false
            NotificationCenter.default.post(name: NSNotification.Name("up_son"), object: nil)
            scrollView.contentOffset = CGPoint(x: 0, y: upTop)
        }
    }
}

1.2设置子视图

此处继承子视图即可,通过通知来改变滑动状态,

class UpSonController: UIViewController {
    
    // MARK: 1.interface
    ///是否允许滚动
    private var canScroll: Bool = false
    
    // MARK: 2.lift cycle
    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(self, selector: #selector(notiScroll), name: NSNotification.Name("up_son"), object: nil)
    }
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    // MARK: 3.private methods
    ///可以滚动接受
    @objc private func notiScroll() {
        canScroll = true
    }
}

extension UpSonController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offSetY = scrollView.contentOffset.y
        if canScroll == false {
            scrollView.contentOffset = CGPoint.zero
        }
        if offSetY < 0 {
            canScroll = false
            NotificationCenter.default.post(name: NSNotification.Name("up_father"), object: nil)
        }
    }
}

1.3使用方法

1.3.1 当前ViewController 继承父视图

同时UItableView 使用 YLGestureTableView

let tableView = YLGestureTableView(frame: view.bounds), style: .plain)

1.3.2当前ViewController 继承父视图

同时UItableView 使用 YLGestureTableView

let tableView = YLGestureTableView(frame: view.bounds), style: .plain)

1.3.3 子视图我放到了cell中,当然,你也可以有其他想法

子视图vc必须放到一个 UIScrollView中,否则影响滑动

class UpCell: UITableViewCell {
     
    // MARK: - 1.lift cycle
    override func hj_setupUI() {
        super.hj_setupUI()
         
        contentView.addSubview(mainScrollView)
        mainScrollView.addSubview(bottomVC.view)
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        mainScrollView.frame = CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height)
        
    }
    // MARK: - 2.getter
    private lazy var mainScrollView: UIScrollView = {
        let scrollview = UIScrollView(frame: bounds)
        scrollview.contentSize = bounds.size
        scrollview.bounces = false
        
        return scrollview
    }()
    
    private lazy var bottomVC: UpBottomController = {
        let vc = UpBottomController()
        vc.view.frame = bounds
        
        return vc
    }()
}

2、UITableView嵌套,从中间下拉刷新

此处略微复杂
我划分为三种状态
0、顶部 全部可见: 可下拉,上拉变 1,默认状态
1、顶部 非全部可见:不可上拉、不可下拉
2、顶部不可见:可上拉,可下拉,下拉contentOffset.y=0 时,变1

2.1 设置父视图

此处继承父视图即可,顶部高度可以自己设置高度,通过通知来改变滑动状态,具体滑动哪个

class CenterFatherController: UIViewController {
    
    // MARK: - 1.interface
    /**
     *  0、顶部 全部可见: 可下拉,上拉变 1
     *  1、顶部 非全部可见:不可上拉、不可下拉
     *  2、顶部不可见:可上拉,可下拉,下拉contentOffset.y=0 时,变1
     */
    public var indexScroll: Int = 0
    ///顶部高度
    public let centerTop: CGFloat = 300
    // MARK: - 2.lift cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        
        NotificationCenter.default.addObserver(self, selector: #selector(notiScroll), name: NSNotification.Name("center_father"), object: nil)
    }
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    // MARK: - 3.private methods
    ///可以滚动接受
    @objc private func notiScroll() {
        indexScroll = 1
    }
}
extension CenterFatherController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offSetY = scrollView.contentOffset.y
        if indexScroll == 2 {
            scrollView.contentOffset = CGPoint(x: 0, y: centerTop)
        } else if (offSetY <= 0) {
            indexScroll = 0
            NotificationCenter.default.post(name: NSNotification.Name("center_son"), object: ["index": 0])
        } else if (offSetY < centerTop) {
            indexScroll = 1
            NotificationCenter.default.post(name: NSNotification.Name("center_son"), object: ["index": 1])
        } else {
            indexScroll = 2
            NotificationCenter.default.post(name: NSNotification.Name("center_son"), object: ["index": 2])
            scrollView.contentOffset = CGPoint(x: 0, y: centerTop)
        }
    }
}

2.2设置子视图

此处继承子视图即可,通过通知来改变滑动状态,

class CenterSonController: UIViewController {
    // MARK: - 1.interface
    /**
     *  0、顶部 全部可见: 可下拉,上拉变 1
     *  1、顶部 非全部可见:不可上拉、不可下拉
     *  2、顶部不可见:可上拉,可下拉,下拉contentOffset.y=0 时,变1
     */
    public var indexScroll: Int = 0
    // MARK: - 2.lift cycle
    override func viewDidLoad() {
        super.viewDidLoad()
   
        NotificationCenter.default.addObserver(self, selector: #selector(notiScroll), name: NSNotification.Name("center_son"), object: nil)
    }
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    // MARK: - 3.private methods
    ///可以滚动接受
    @objc private func notiScroll(_ noti: Notification) {
        if let object = noti.object as? [String: Int] {
            let index = object["index"] ?? 0
            indexScroll = index
        }
    }
}

extension CenterSonController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offsetY = scrollView.contentOffset.y
        switch indexScroll {
        case 0:
            if offsetY > 0 {
                indexScroll = 1
                scrollView.setContentOffset(CGPoint.zero, animated: false)
                NotificationCenter.default.post(name: NSNotification.Name("center_father"), object:nil)
            }
        case 1:
            scrollView.setContentOffset(CGPoint.zero, animated: false)
        default:
            if offsetY < 0 {
                indexScroll = 1
                scrollView.setContentOffset(CGPoint.zero, animated: false)
                NotificationCenter.default.post(name: NSNotification.Name("center_father"), object: nil)
            }
        }
        
    }
}

2.3使用方法

使用方法完全和1.3一致,请看上文

demo

嗯,感觉这个东西逻辑有点头疼,而且我此篇文章描述的很烂,文章我尽量改吧,大家还是看demo吧,demo上展示的清清楚楚的
demo 传送门

嗯,由于上面giee开源一直有问题,可以来下面CSDN上下载链接下载,免积分的
HJScrollView