众所周知,UITableView和UICollectionView都继承于UIScrollView,实际本文说的就是UIScrollView嵌套UIScrollView的事。
首先,自定义NestScrollView继承于UIScrollView,实现UIGestureRecognizerDelegate协议中的方法允许手势同时识别。
import Foundation
import UIKit
class NestScrollView: UIScrollView {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
}
extension NestScrollView: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
底层,让scrollView继承NestScrollView,实现scrollViewDidScroll:方法,然后接收"ScrollViewCanScroll"通知。
import Foundation
import UIKit
class GAListVC: UIViewController {
@IBOutlet weak var scrollView: NestScrollView!
@IBOutlet weak var bgHConstraint: NSLayoutConstraint!
@IBOutlet weak var bgView: UIView!
private var canScroll: Bool = true
private lazy var headerView: UIView = {
let view = Bundle.main.loadNibNamed("GAHeaderView", owner: nil, options: nil)![0] as! GAHeaderView
return view
}()
private lazy var contentVC: GAContentVC = {
let vc = GAContentVC()
return vc
}()
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
NotificationCenter.default.addObserver(self, selector: #selector(ScrollViewCanScroll(_:)), name: NSNotification.Name("ScrollViewCanScroll"), object: nil)
}
@objc private func ScrollViewCanScroll(_ notifi: Notification) {
canScroll = true
}
private func setupUI() {
self.navigationController?.isNavigationBarHidden = true
if #available(iOS 11.0, *){
scrollView.contentInsetAdjustmentBehavior = .never
} else {
self.automaticallyAdjustsScrollViewInsets = false
}
let headerHeigth: CGFloat = 200.0
headerView.frame = CGRect(x: 0, y: 0, width: UIDevice.screenWidth(), height: headerHeigth)
bgView.addSubview(headerView)
let contentHeight: CGFloat = UIDevice.screenHeight() - UIDevice.statusBarHeight()
contentVC.view.frame = CGRect(x: 0, y: headerHeigth, width: UIDevice.screenWidth(), height: contentHeight)
bgView.addSubview(contentVC.view)
contentVC.startReloadVC()
let bgHeight: CGFloat = headerHeigth + contentHeight
bgHConstraint.constant = bgHeight
}
}
extension GAListVC: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let topOffset: CGFloat = 200.0 - UIDevice.statusBarHeight()
if self.canScroll == false {
scrollView.contentOffset = CGPoint(x: 0, y: topOffset)
} else if (scrollView.contentOffset.y >= topOffset) {
scrollView.contentOffset = CGPoint(x: 0, y: topOffset)
self.canScroll = false
NotificationCenter.default.post(name: NSNotification.Name("TableViewCanScroll"), object: nil, userInfo: nil)
}
}
}
内层,就实现scrollViewDidScroll:方法,然后接收"TableViewCanScroll"通知。
import Foundation
import UIKit
class GAContentVC: UIViewController {
@IBOutlet weak var cateTableView: UITableView!
@IBOutlet weak var listTableView: UITableView!
private var dataArray: [GACategoryModel] = []
private var tableCanScroll: Bool = false
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
tableCanScroll = false
NotificationCenter.default.addObserver(self, selector: #selector(tableViewCanScroll(_:)), name: NSNotification.Name("TableViewCanScroll"), object: nil)
}
@objc private func tableViewCanScroll(_ notifi: Notification) {
tableCanScroll = true
}
func startReloadVC() {
}
}
extension GAContentVC: UITableViewDelegate, UITableViewDataSource {
......
}
extension GAContentVC: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if tableCanScroll == false {
scrollView.contentOffset = CGPoint.zero
} else if (scrollView.contentOffset.y <= 0) {
tableCanScroll = false
NotificationCenter.default.post(name: NSNotification.Name("ScrollViewCanScroll"), object: nil, userInfo: nil)
}
}
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
if scrollView == cateTableView {
let listOffset = listTableView.contentOffset
if listOffset.y == 0 {
let scrEnabled = listTableView.isScrollEnabled
listTableView.isScrollEnabled = false
listTableView.contentOffset = CGPoint(x: listOffset.x, y: 1)
listTableView.isScrollEnabled = scrEnabled
}
} else {
let cateOffset = cateTableView.contentOffset
if cateOffset.y == 0 {
let scrEnabled = cateTableView.isScrollEnabled
cateTableView.isScrollEnabled = false
cateTableView.contentOffset = CGPoint(x: cateOffset.x, y: 1)
cateTableView.isScrollEnabled = scrEnabled
}
}
}
}
Demo GitHub: https://github.com/Gamin-fzym/GAScrollViewNestDemo
Demo示意图: 同理,也能实现这样的页面效果。
|