tableView与collectionView联动功能的实现(左侧大分类,右侧小分类)

protocol TableWithCollectionViewDelegate: NSObjectProtocol {
    func collectionView(didSelectItemAt indexPath: IndexPath)
}

class TableWithCollectionView: UIView {
    weak var delegate: TableWithCollectionViewDelegate?
    var leftModels: [String] = []{
        didSet{
            tableView.reloadData()
            tableView.selectRow(at: IndexPath(row: currentIndex, section: 0), animated: false, scrollPosition: .none)
        }
    }
    var rightModels: [[String]] = []{
        didSet{
            collectionView.reloadData()
        }
    }
    
    
    private var currentIndex: Int = 0 //tableView当前选中的index
    private var sectionInsets: CGFloat = 10~
    private var tableView: BaseTableView!
    private var collectionView: UICollectionView!
    //右侧collectionView当前是否正在向下滚动(即true表示手指向上滑动,查看下面内容)
    private var collectionViewIsScrollDown = true
    //右侧collectionView垂直偏移量
    private var collectionViewLastOffsetY : CGFloat = 0.0
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUI()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setUI()
    }
}
extension TableWithCollectionView{
    private func setUI(){
        setTableView()
        setCollectionView()
    }
    private func setTableView(){
        tableView = BaseTableView()
        tableView.backgroundColor = .cWhite
        tableView.delegate = self
        tableView.dataSource = self
        tableView.isNoDate = false
        tableView.bounces = false
        tableView.register(LTitleCell.self, forCellReuseIdentifier: LTitleCell.cellID)
        self.addSubview(tableView)
        tableView.snp.makeConstraints { make in
            make.top.leading.bottom.equalToSuperview()
            make.width.equalTo(88~)
        }
    }
    private func setCollectionView(){
        let layout = JJCollectionViewRoundFlowLayout_Swift()
        layout.isCalculateHeader = false
        layout.isCalculateFooter = false
        layout.sectionHeadersPinToVisibleBounds = true
        layout.scrollDirection = .vertical
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.contentInsetAdjustmentBehavior = .never
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.bounces = false
        collectionView.backgroundColor = .bgColor2
        collectionView.showsVerticalScrollIndicator = false
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.register(RCollectionCell.self, forCellWithReuseIdentifier: RCollectionCell.cellID)
        collectionView.register(RCollectionSectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: RCollectionSectionHeader.cellID)
        collectionView.register(RCollectionSectionFooter.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: RCollectionSectionFooter.cellID)
        self.addSubview(collectionView)
        collectionView.snp.makeConstraints { make in
            make.top.bottom.equalTo(tableView)
            make.trailing.equalToSuperview().inset(10~)
            make.leading.equalTo(tableView.snp.trailing).offset(10~)
        }
    }
}

//MARK: -UITableView
extension TableWithCollectionView: UITableViewDelegate, UITableViewDataSource{
    //将右侧colletionView的指定分区自动滚动到最顶端
    func collectionViewScrollToTop(section: Int, animated: Bool) {
        let rectY = collectionViewHeaderFrame(section: section)
        let topOfHeader = CGPoint(x: 0, y: rectY - collectionView.contentInset.top)
        collectionView.setContentOffset(topOfHeader, animated: animated)
    }
    //获取colletionView的指定分区头的高度
    func collectionViewHeaderFrame(section: Int) -> CGFloat {
        let indexPath = IndexPath(item: 0, section: section)
        let firstCell = collectionView.collectionViewLayout.layoutAttributesForItem(at: indexPath)
        let attributes = collectionView.collectionViewLayout
            .layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath)
        guard let yForFirstCell = firstCell?.frame.minY else {
            return .zero
        }
        guard let heightForHeader = attributes?.frame.height else {
            return .zero
        }
        return yForFirstCell - heightForHeader - sectionInsets
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //右侧collection自动滚动到对应的分区
        collectionViewScrollToTop(section: indexPath.row, animated: true)
        currentIndex = indexPath.row
        tableView.reloadData()
        tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        leftModels.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: LTitleCell.cellID, for: indexPath) as!
        LTitleCell
        cell.title = leftModels[indexPath.row]
        return cell
    }
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        let cell = cell as! LTitleCell
        switch indexPath.row {
        case currentIndex - 1:
            cell.bgView.layer.cornerRadius = 5~
            cell.bgView.layer.maskedCorners = CACornerMask(rawValue: CACornerMask.layerMaxXMaxYCorner.rawValue)
        case currentIndex + 1:
            cell.bgView.layer.cornerRadius = 5~
            cell.bgView.layer.maskedCorners = CACornerMask(rawValue: CACornerMask.layerMaxXMinYCorner.rawValue)
        default:
            cell.bgView.layer.cornerRadius = 0
        }
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        50~
    }
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        UIView()
    }
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        10~
    }
}

//MARK: -UICollectionView
extension TableWithCollectionView: UICollectionViewDelegate, UICollectionViewDataSource, JJCollectionViewDelegateRoundFlowLayout_Swift{
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        delegate?.collectionView(didSelectItemAt: indexPath)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, configModelForSectionAtIndex section: Int) -> JJCollectionViewRoundConfigModel_Swift {
        let model = JJCollectionViewRoundConfigModel_Swift.init()
        model.backgroundColor = UIColor.cWhite
        model.cornerRadius = 10~
        return model
    }
    
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        rightModels.count
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        rightModels[section].count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let item = collectionView.dequeueReusableCell(withReuseIdentifier: RCollectionCell.cellID, for: indexPath) as! RCollectionCell
        item.model = rightModels[indexPath.section][indexPath.item]
        return item
    }
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        if kind == UICollectionView.elementKindSectionHeader {
            let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: RCollectionSectionHeader.cellID, for: indexPath) as! RCollectionSectionHeader
            //设置分组标题
            header.titleLabel.text = leftModels[indexPath.section]
            return header
        }else {
            return collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: RCollectionSectionFooter.cellID, for: indexPath) as! RCollectionSectionFooter
        }
    }
    
    //返回分组头大小
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.bounds.width, height: 40~)
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.bounds.width, height: section == collectionView.numberOfSections - 1 ? 10~ : 0.01)
    }
    
    //返回单元格大小
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let itemWidth = (collectionView.bounds.width - 20~) / 3
        let itemHeight = itemWidth / 3 * 4
        return CGSize(width: itemWidth, height: itemHeight)
    }
    
    //每个分组的内边距
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets.init(top: sectionInsets, left: sectionInsets, bottom: sectionInsets, right: sectionInsets)
    }
    
    //单元格的行间距
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 1.0
    }
    
    //单元格横向的最小间距
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0.0
    }
    //分区头即将要显示时调用
    func collectionView(_ collectionView: UICollectionView,
                        willDisplaySupplementaryView view: UICollectionReusableView,
                        forElementKind elementKind: String, at indexPath: IndexPath) {
        //如果是由用户手动滑动屏幕造成的向上滚动,那么左侧表格自动选中该分区对应的分类
        if !collectionViewIsScrollDown
            && (collectionView.isDragging || collectionView.isDecelerating) {
            currentIndex = indexPath.section
            tableView.reloadData()
            tableView.selectRow(at: IndexPath(row: currentIndex, section: 0),
                                animated: true, scrollPosition: .top)
        }
    }
    //分区头即将要消失时调用
    func collectionView(_ collectionView: UICollectionView,
                        didEndDisplayingSupplementaryView view: UICollectionReusableView,
                        forElementOfKind elementKind: String, at indexPath: IndexPath) {
        //如果是由用户手动滑动屏幕造成的向下滚动,那么左侧表格自动选中该分区对应的下一个分区的分类
        if collectionViewIsScrollDown && (collectionView.isDragging || collectionView.isDecelerating) {
            currentIndex = indexPath.section + 1
            tableView.reloadData()
            tableView.selectRow(at: IndexPath(row: currentIndex, section: 0), animated: true, scrollPosition: .top)
        }
    }
    
    //视图滚动时触发(主要用于记录当前collectionView是向上还是向下滚动)
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if collectionView == scrollView {
            collectionViewIsScrollDown = collectionViewLastOffsetY < scrollView.contentOffset.y
            collectionViewLastOffsetY = scrollView.contentOffset.y
        }
    }
}

其中JJCollectionViewDelegateRoundFlowLayout_Swift是用于设置UIcollectionView的section底色,圆角

tableView与collectionView联动功能的实现(左侧大分类,右侧小分类)

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...