Интерфейс потока UICollectionViewController с читаемой шириной содержимого
У меня есть UICollectionView
использующий макет потока, и я пытаюсь достичь тех же полей, что и UITableViewController
с читаемой шириной содержимого.
Самое близкое, с чем я столкнулся, чтобы соответствовать этому поведению макета, - это встроить UICollectionViewController
в UIViewController
и иметь встроенное представление "Follow Readable Width".
![UICollectionViewController embedded in UIViewController]()
Здесь цвет бирюзового цвета - UIViewController
а цвет лосося - UICollectionViewController
. Проблема в том, что UICollectionView
область не прокручивает UICollectionView
а индикаторы прокрутки также расположены не по краю экрана, как вы ожидаете.
Мой вопрос:
Как я могу достичь этого макета без необходимости встраивать UICollectionViewController
?
Я предполагаю, что я могу как-то установить UICollectionView
левого и правого разделов UICollectionView так, чтобы они соответствовали читаемым полям направляющих контента, и обновить их, переопределив viewWillTransition(to size: with coordinator:)
и наблюдая уведомления UIContentSizeCategoryDidChange
, но я не уверен, что делать об этом.
Ответы
Ответ 1
Вы понимаете, правильно, самый простой способ сделать это через представление коллекции insetForSection
. По моему опыту, требуется следующее:
- Возвращает вид коллекции
directionalLayoutMargins
как вставка (использование .leading
и. trailing
- Отключить автоматическую обработку безопасной области через
collectionView.insetsLayoutMarginsFromSafeArea = false
- Вручную установите вид коллекции
directionalLayoutMargins
используя view.readableContentGuide.layoutFrame.origin.x
. Обратите внимание, что я использую view.readableContentGuide, а не collectionView
. - Обновляйте
directionalLayoutMargins
точно таким же образом всякий раз, когда viewLayoutMarginsDidChange
Тем не менее, было бы неплохо узнать, как это сделать без каких-либо контейнеров.
Ответ 2
Для того, чтобы решить проблему с Swift 5.1 и прошивкой 13, вы можете настроить макет потока sectionInsetReference
свойства .fromLayoutMargins
, установить коллекцию вида insetsLayoutMarginsFromSafeArea
свойство false
и установить представление коллекции layoutMargins
свойство, чтобы соответствовать readableContentGuide
врезки.
Два следующих примера кода показывают возможные реализации, чтобы иметь представление коллекции, которое имеет читаемую ширину содержимого.
# 1. Использование UICollectionViewDelegateFlowLayout
import UIKit
class CollectionViewController: UICollectionViewController {
let inset: CGFloat = 10
let minimumLineSpacing: CGFloat = 10
let minimumInteritemSpacing: CGFloat = 10
let cellsPerRow = 5
override func viewDidLoad() {
super.viewDidLoad()
title = "Demo"
guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
layout.sectionInsetReference = .fromLayoutMargins
collectionView.insetsLayoutMarginsFromSafeArea = false
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
override func viewWillLayoutSubviews() {
let xOrigin = view.readableContentGuide.layoutFrame.origin.x
collectionView.layoutMargins = UIEdgeInsets(top: 0, left: xOrigin, bottom: 0, right: xOrigin)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
}
extension CollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: inset, left: inset, bottom: inset, right: inset)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return minimumLineSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return minimumInteritemSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let marginsAndInsets = inset * 2 + collectionView.layoutMargins.left + collectionView.layoutMargins.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
return CGSize(width: itemWidth, height: itemWidth)
}
}
# 2. Подклассы UICollectionViewFlowLayout
ColumnFlowLayout.swift
import UIKit
class ColumnFlowLayout: UICollectionViewFlowLayout {
let cellsPerRow: Int
init(cellsPerRow: Int, minimumInteritemSpacing: CGFloat = 0, minimumLineSpacing: CGFloat = 0, sectionInset: UIEdgeInsets = .zero) {
self.cellsPerRow = cellsPerRow
super.init()
self.sectionInsetReference = .fromLayoutMargins
self.minimumInteritemSpacing = minimumInteritemSpacing
self.minimumLineSpacing = minimumLineSpacing
self.sectionInset = sectionInset
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
super.prepare()
guard let collectionView = collectionView else { return }
let marginsAndInsets = sectionInset.left + sectionInset.right + collectionView.layoutMargins.left + collectionView.layoutMargins.right + minimumInteritemSpacing * CGFloat(cellsPerRow - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(cellsPerRow)).rounded(.down)
itemSize = CGSize(width: itemWidth, height: itemWidth)
}
}
CollectionViewController.swift
import UIKit
class CollectionViewController: UICollectionViewController {
let columnLayout = ColumnFlowLayout(
cellsPerRow: 5,
minimumInteritemSpacing: 10,
minimumLineSpacing: 10,
sectionInset: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
)
override func viewDidLoad() {
super.viewDidLoad()
title = "Demo"
collectionView.collectionViewLayout = columnLayout
collectionView.insetsLayoutMarginsFromSafeArea = false
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
override func viewWillLayoutSubviews() {
let xOrigin = view.readableContentGuide.layoutFrame.origin.x
collectionView.layoutMargins = UIEdgeInsets(top: 0, left: xOrigin, bottom: 0, right: xOrigin)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 59
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.orange
return cell
}
}
Показать на iPhone Xs Max:
![enter image description here]()