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底色,圆角