Open popeyelau opened 5 years ago
import UIKit class CategoryViewController: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var collectionView: UICollectionView! var collectionViewIsScrollDown: Bool = false var collectionViewLastOffsetY: CGFloat = 0 var categories: [String] = [] override func viewDidLoad() { super.viewDidLoad() tableView.tableFooterView = UIView() tableView.separatorColor = .white tableView.backgroundColor = .groupTableViewBackground tableView.showsVerticalScrollIndicator = false tableView.scrollsToTop = false tableView.register(CategoryTableViewCell.self, forCellReuseIdentifier: "cell") collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "cell") collectionView.register(CollectionViewSectionHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "header") if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { let width = (UIScreen.main.bounds.width - tableView.frame.width - 16) / 3 let height = width + 10 layout.itemSize = CGSize(width: width, height: height) layout.sectionInset = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4) layout.minimumLineSpacing = 2 layout.minimumInteritemSpacing = 2 layout.sectionHeadersPinToVisibleBounds = true layout.headerReferenceSize = CGSize(width: collectionView.frame.width, height: 44) } categories = (1...20).map{ "分类\($0)" } tableView.selectRow(at: IndexPath(row: 0, section: 0), animated: true, scrollPosition: .none) } } extension CategoryViewController: UITableViewDataSource, UITableViewDelegate { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return categories.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = categories[indexPath.row] return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { collectionViewScrollToTop(at: indexPath.row) tableView.scrollToRow(at: indexPath, at: .top, animated: true) } } extension CategoryViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { func numberOfSections(in collectionView: UICollectionView) -> Int { return categories.count } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 15 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell return cell } func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "header", for: indexPath) as! CollectionViewSectionHeader header.titleLabel.text = categories[indexPath.section] return header } func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath) { if !collectionViewIsScrollDown && (collectionView.isDragging || collectionView.isDecelerating) { tableView.selectRow(at: IndexPath(row: indexPath.section, 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) { tableView.selectRow(at: IndexPath(row: indexPath.section + 1, section: 0), animated: true, scrollPosition: .top) } } func scrollViewDidScroll(_ scrollView: UIScrollView) { guard scrollView == collectionView else { return } let offsetY = scrollView.contentOffset.y collectionViewIsScrollDown = collectionViewLastOffsetY < offsetY collectionViewLastOffsetY = offsetY } func scrollViewDidScrollToTop(_ scrollView: UIScrollView) { guard scrollView == collectionView, !categories.isEmpty else { return } tableView.selectRow(at: IndexPath(row: 0, section: 0), animated: false, scrollPosition: .none) } } extension CategoryViewController { func collectionViewScrollToTop(at section: Int, animated: Bool = true) { let headerRect = collectionViewHeaderFrame(at: section) let top = CGPoint(x: 0, y: headerRect.origin.y - collectionView.contentInset.top) collectionView.setContentOffset(top, animated: animated) } func collectionViewHeaderFrame(at section: Int) -> CGRect { let indexPath = IndexPath(item: 0, section: section) let attributes = collectionView.collectionViewLayout.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath) guard let firstCellFrame = attributes?.frame else { return .zero } return firstCellFrame } } class CategoryTableViewCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } func setup() { textLabel?.font = .systemFont(ofSize: 12) textLabel?.textAlignment = .center backgroundColor = .groupTableViewBackground } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) contentView.backgroundColor = selected ? .white : .groupTableViewBackground isHighlighted = selected } } class CollectionViewSectionHeader: UICollectionReusableView { lazy var titleLabel: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 12) label.translatesAutoresizingMaskIntoConstraints = false return label }() override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } func setup() { backgroundColor = .groupTableViewBackground addSubview(titleLabel) titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true titleLabel.rightAnchor.constraint(lessThanOrEqualTo: rightAnchor, constant: -8).isActive = true } } class CollectionViewCell: UICollectionViewCell { lazy var imageView: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "demo") imageView.translatesAutoresizingMaskIntoConstraints = false return imageView }() lazy var titleLabel: UILabel = { let label = UILabel() label.text = "#Hello#" label.textAlignment = .center label.font = .systemFont(ofSize: 12) label.translatesAutoresizingMaskIntoConstraints = false return label }() override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } func setup() { addSubview(imageView) addSubview(titleLabel) imageView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true imageView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true imageView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true titleLabel.topAnchor.constraint(greaterThanOrEqualTo: imageView.bottomAnchor, constant: 8).isActive = true titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8).isActive = true } }