У меня есть контроллер вида, который состоит из UICollectionView
с 3 секциями (каждая с UITableView
внутри). Первый раздел довольно динамический c с данными, загруженными асинхронно из Интернета и вставляемыми методом self.tableView.insertItems()
. Первые разделы обновляются правильно, и элементы добавляются в представление, но другие разделы не перемещаются, пока я не прокручиваю представление (Разделы 2 и 3 правильно переходят в нижнюю часть представления при прокрутке).
Итак, при запуске I в конечном итоге с результатом ниже (изображение). Конечно, использование self.collectionView.reloadData()
сразу после self.tableView.insertItems()
работает, но мне кажется немного странным. Может кто-нибудь указать мне на лучшее решение? Я могу предоставить пример проекта, если необходимо.
class ViewController: BaseViewController {
static let firstCellId = "firstCellId"
static let secondCellId = "secondCellId"
static let thirdCellId = "thirdCellId"
private weak var collectionView: UICollectionView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Title"
self.setupCollectionView()
private func setupCollectionView() {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.estimatedItemSize = CGSize(width: self.view.frame.width, height: 1.0)
flowLayout.scrollDirection = .vertical
flowLayout.minimumInteritemSpacing = 0.0
flowLayout.minimumLineSpacing = 0.0
let collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: flowLayout)
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "Background")
collectionView.backgroundView = imageView
let blurEffect = UIBlurEffect(style: .dark)
let visualEffectView = UIVisualEffectView(effect: blurEffect)
collectionView.backgroundView?.addSubview(visualEffectView)
visualEffectView.fillSuperview()
collectionView.alwaysBounceVertical = true
collectionView.register(
LibrarySectionHeaderView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: LibrarySectionHeaderView.librarySectionHeaderId
)
collectionView.register(FirstTableViewCell.self, forCellWithReuseIdentifier: ViewController.firstCellId)
collectionView.register(SecondTableViewCell.self, forCellWithReuseIdentifier: ViewController.secondCellId)
collectionView.register(ThirdTableViewCell.self, forCellWithReuseIdentifier: ViewController.thirdCellId)
self.view.addSubview(collectionView)
self.collectionView = collectionView
self.collectionView.translatesAutoresizingMaskIntoConstraints = false
self.collectionView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
self.collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
self.collectionView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.collectionView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
}
// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: self.view.frame.width, height: 61.0)
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: LibrarySectionHeaderView.librarySectionHeaderId, for: indexPath) as! LibrarySectionHeaderView
switch indexPath.section {
case 0:
header.uiLabel.text = "Section 1"
case 1:
header.uiLabel.text = "Section 2"
case 2:
header.uiLabel.text = "Section 3"
default:
fatalError("Unsupported section index.")
}
return header
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.section {
case 0:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewController.firstCellId, for: indexPath) as! FirstTableViewCell
self.firstTableViewCell = cell
cell.setTableViewDelegates(dataSourceDelegate: self.firstSource, viewDelegate: self.firstSource)
return cell
case 1:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewController.secondCellId, for: indexPath) as! SecondTableViewCell
cell.setTableViewDelegates(dataSourceDelegate: self.secondSource, viewDelegate: self.secondSource)
return cell
case 2:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewController.thirdTableCellId, for: indexPath) as! ThirdTableViewCell
cell.setTableViewDelegates(dataSourceDelegate: self.thirdSource, viewDelegate: self.thirdSource)
return cell
default:
fatalError("Unsupported section index!")
}
}
}
FirstTableViewCell в основном похож на Second:
class SecondTableViewCell: UICollectionViewCell {
static let firstSubCellId = "firstSubCellId"
lazy var width: NSLayoutConstraint = {
let width = self.contentView.widthAnchor.constraint(equalToConstant: self.bounds.size.width)
width.isActive = true
return width
}()
private weak var tableView: ContentSizedTableView!
override init(frame: CGRect) {
super.init(frame: frame)
self.setupTableView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupTableView() {
let tableView = ContentSizedTableView(frame: self.frame, style: .plain)
tableView.backgroundColor = .clear
tableView.isScrollEnabled = false
tableView.register(SecondTableViewRowCell.self, forCellReuseIdentifier: SecondTableViewCell.firstSubCellId)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(tableView)
self.tableView = tableView
self.tableView.translatesAutoresizingMaskIntoConstraints = false
self.tableView.topAnchor.constraint(equalTo: self.contentView.topAnchor).isActive = true
self.tableView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
self.tableView.leftAnchor.constraint(equalTo: self.contentView.leftAnchor).isActive = true
self.tableView.rightAnchor.constraint(equalTo: self.contentView.rightAnchor).isActive = true
tableView.separatorStyle = .singleLine
tableView.separatorColor = .tableSeparatorColor
}
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
self.width.constant = bounds.size.width
return self.contentView.systemLayoutSizeFitting(CGSize(width: targetSize.width, height: 1.0))
}
func deselectLastSelectedRow() {
guard let lastRow = self.tableView.indexPathForSelectedRow else { return }
self.tableView.deselectRow(at: lastRow, animated: true)
}
}
class ContentSizedTableView: UITableView {
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
self.estimatedRowHeight = UITableView.automaticDimension
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var contentSize: CGSize {
didSet {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: self.contentSize.height)
}
}