Как центрировать горизонтальные ячейки UICollectionView?
Я провел некоторое исследование, но не смог найти пример кода о том, как горизонтально размещать ячейки в UICollectionView.
вместо первой ячейки, подобной этой X00, я хочу, чтобы она была такой 0X0. есть ли способ сделать это?
EDIT:
чтобы визуализировать то, что я хочу:
![введите описание изображения здесь]()
Мне нужно, чтобы он выглядел как версия B, когда в CollectionView есть только один элемент. Когда я получил более одного элемента, тогда он должен быть похож на версию A, но с большим количеством элементов.
На данный момент это выглядит как версия A, когда у меня есть только один элемент, и мне интересно, как я могу сделать его похожим на B.
Спасибо за помощь!
Ответы
Ответ 1
Не стоит использовать библиотеку, если ваша цель только в этом, то есть выравнивание по центру.
Лучше вы можете сделать этот простой расчет в вашей функции collectionViewLayout.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let totalCellWidth = CellWidth * CellCount
let totalSpacingWidth = CellSpacing * (CellCount - 1)
let leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
Ответ 2
Swift 4.2
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)
let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
Свифт 3
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)
let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
не забудьте добавить протокол
UICollectionViewDelegateFlowLayout
Ответ 3
Попробуйте это для Swift 4
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let cellWidth : CGFloat = 165.0
let numberOfCells = floor(self.view.frame.size.width / cellWidth)
let edgeInsets = (self.view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)
return UIEdgeInsetsMake(15, edgeInsets, 0, edgeInsets)
}
Добавьте свой cellWidth вместо 165.0
Ответ 4
Я использую KTCenterFlowLayout для этого, и он отлично работает. Это пользовательский подкласс UICollectionViewFlowLayout
, который центрирует ячейки по вашему желанию. (Примечание: это не тривиальная вещь, которую можно решить, разместив код, поэтому я связываюсь с проектом GitHub!)
Ответ 5
Версия объективной версии Darshan Patel:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
CGFloat totalCellWidth = kItemWidth * self.dataArray.count;
CGFloat totalSpacingWidth = kSpacing * (((float)self.dataArray.count - 1) < 0 ? 0 :self.dataArray.count - 1);
CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
CGFloat rightInset = leftInset;
UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
return sectionInset;
}
Ответ 6
Немного изменяя ответ @Safad Funy, это то, что сработало для меня в последней версии Swift и iOS. В этом случае я хотел, чтобы ширина ячеек составляла треть от размера вида коллекции.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let totalCellWidth = Int(collectionView.layer.frame.size.width) / 3 * collectionView.numberOfItems(inSection: 0)
let totalSpacingWidth = (collectionView.numberOfItems(inSection: 0) - 1)
let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
Ответ 7
Вы можете использовать это расширение (Swift 4).
Он может центрировать клетки с, если вы collectionView
имеют layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
.
Он работает с любым размером ячеек и отлично работает, когда scrollDirection =.horizontal
public extension UICollectionView {
func centerContentHorizontalyByInsetIfNeeded(minimumInset: UIEdgeInsets) {
guard let layout = collectionViewLayout as? UICollectionViewFlowLayout,
layout.scrollDirection == .horizontal else {
assertionFailure("\(#function): layout.scrollDirection != .horizontal")
return
}
if layout.collectionViewContentSize.width > frame.size.width {
contentInset = minimumInset
} else {
contentInset = UIEdgeInsets(top: minimumInset.top,
left: (frame.size.width - layout.collectionViewContentSize.width) / 2,
bottom: minimumInset.bottom,
right: 0)
}
}
}
final class Foo: UIViewController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.centerContentHorizontalyByInsetIfNeeded(minimumInset: yourDefaultInset)
}
}
Надеюсь, это поможет вам!
Ответ 8
Swift 4
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let cellWidth: CGFloat = 170.0 // Your cell width
let numberOfCells = floor(view.frame.size.width / cellWidth)
let edgeInsets = (view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)
return UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets)
}
}
Ответ 9
Вы можете попробовать мое решение, оно отлично работает,
func refreshCollectionView(_ count: Int) {
let collectionViewHeight = collectionView.bounds.height
let collectionViewWidth = collectionView.bounds.width
let numberOfItemsThatCanInCollectionView = Int(collectionViewWidth / collectionViewHeight)
if numberOfItemsThatCanInCollectionView > count {
let totalCellWidth = collectionViewHeight * CGFloat(count)
let totalSpacingWidth: CGFloat = CGFloat(count) * (CGFloat(count) - 1)
// leftInset, rightInset are the global variables which I am passing to the below function
leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2;
rightInset = -leftInset
} else {
leftInset = 0.0
rightInset = -collectionViewHeight
}
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
Ответ 10
Принятый ответ - правильный ответ, но если ваш totalCellWidth
меньше width
CollectionView
, но для защиты от этого вы можете сделать, как totalCellWidth
ниже.
if (leftInset > 0) {
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
} else {
return UIEdgeInsetsMake(0, 10, 0, 10)
}
Ответ 11
Для людей, которые только хотят добавить отступы (сверху, влево, снизу, справа):
Добавить протокол UICollectionViewDelegateFlowLayout
Этот пример показывает прописку слева и справа с 40.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 40, 0, 40)
}
Ответ 12
SWIFT 4.2
private lazy var contentView: UICollectionView = {
let layoutView: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layoutView.scrollDirection = .horizontal
layoutView.minimumInteritemSpacing = 0
layoutView.minimumLineSpacing = 5
let collectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: layoutView)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.showsHorizontalScrollIndicator = false
collectionView.isPagingEnabled = true
collectionView.registerCell(Cell.self)
collectionView.backgroundColor = .clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
//
extension CustomCollectionView: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width*4/5, height: collectionView.frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let cellWidth : CGFloat = collectionView.frame.width*4/5
let numberOfCells = floor(collectionView.frame.width / cellWidth)
let edgeInsets = (collectionView.frame.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)
return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: edgeInsets)
}
}
Ответ 13
Этот код должен располагаться в горизонтальном представлении коллекции даже в Swift 4.0 без каких-либо изменений:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let cellWidth: CGFloat = flowLayout.itemSize.width
let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
var collectionWidth = collectionView.frame.size.width
if #available(iOS 11.0, *) {
collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
}
let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
if totalWidth <= collectionWidth {
let edgeInset = (collectionWidth - totalWidth) / 2
return UIEdgeInsetsMake(flowLayout.sectionInset.top, edgeInset, flowLayout.sectionInset.bottom, edgeInset)
} else {
return flowLayout.sectionInset
}
}
Убедитесь, что ваш класс соответствует протоколу UICollectionViewDelegateFlowLayout
Ответ 14
Если ваш не подклассифицирующий UICollectionViewController
, убедитесь, что ваш класс соответствует UICollectionViewDelegateFlowLayout
затем используйте эту функцию в swift 3.0 или новее:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
Ответ 15
Swift 4.2 (по горизонтали и вертикали). Это небольшое обновление кода Pink Panther и большое ему спасибо!
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let cellWidth: CGFloat = flowLayout.itemSize.width
let cellHieght: CGFloat = flowLayout.itemSize.height
let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
var collectionWidth = collectionView.frame.size.width
var collectionHeight = collectionView.frame.size.height
if #available(iOS 11.0, *) {
collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
collectionHeight -= collectionView.safeAreaInsets.top + collectionView.safeAreaInsets.bottom
}
let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
let totalHieght = cellHieght * cellCount + cellSpacing * (cellCount - 1)
if totalWidth <= collectionWidth {
let edgeInsetWidth = (collectionWidth - totalWidth) / 2
print(edgeInsetWidth, edgeInsetWidth)
return UIEdgeInsets(top: 5, left: edgeInsetWidth, bottom: flowLayout.sectionInset.top, right: edgeInsetWidth)
} else {
let edgeInsetHieght = (collectionHeight - totalHieght) / 2
print(edgeInsetHieght, edgeInsetHieght)
return UIEdgeInsets(top: edgeInsetHieght, left: flowLayout.sectionInset.top, bottom: edgeInsetHieght, right: flowLayout.sectionInset.top)
}
}
Убедитесь, что ваш класс соответствует протоколу UICollectionViewDelegateFlowLayout
Ответ 16
В итоге я выбрал совершенно другой подход, о котором, я думаю, стоит упомянуть.
Я установил ограничение на представление моей коллекции, чтобы оно было выровнено по центру по горизонтали. Затем я установил другое ограничение, определяющее ширину. Я создал выход для ограничения ширины внутри моего viewController, который содержит представление коллекции. Затем, когда мой источник данных изменяется, и я обновляю представление сбора, я беру количество ячеек и делаю (очень похожие) вычисления, чтобы сбросить ширину.
let newWidth = (items.count * cellWidth) + (items.count * cellSpacing)
Затем я устанавливаю значение .constant
для выхода ограничения в результат вычисления, а автопоставка сделает все остальное.
Это может конфликтовать с UICollectionViewDelegateFlowLayout, но это отлично сработало для меня, чтобы создать выравнивание по левому краю. Без делегата это работает только тогда, когда ячейки заполняют большую часть представления.
Ответ 17
Общее решение для разметки, которое центрирует страницы, если они меньше ширины, и выравнивает по левому краю, если их больше
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// Centering if there are fever pages
CGSize itemSize = [(UICollectionViewFlowLayout *)collectionViewLayout itemSize];
CGFloat spacing = [(UICollectionViewFlowLayout *)collectionViewLayout minimumLineSpacing];
NSInteger count = [self collectionView:self numberOfItemsInSection:section];
CGFloat totalCellWidth = itemSize.width * count;
CGFloat totalSpacingWidth = spacing * ((count - 1) < 0 ? 0 : count - 1);
CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
if (leftInset < 0) {
UIEdgeInsets inset = [(UICollectionViewFlowLayout *)collectionViewLayout sectionInset];
return inset;
}
CGFloat rightInset = leftInset;
UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
return sectionInset;
}
Swift версия (конвертированная из ObjC)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
// Centering if there are fever pages
let itemSize: CGSize? = (collectionViewLayout as? UICollectionViewFlowLayout)?.itemSize
let spacing: CGFloat? = (collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing
let count: Int = self.collectionView(self, numberOfItemsInSection: section)
let totalCellWidth = (itemSize?.width ?? 0.0) * CGFloat(count)
let totalSpacingWidth = (spacing ?? 0.0) * CGFloat(((count - 1) < 0 ? 0 : count - 1))
let leftInset: CGFloat = (bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2
if leftInset < 0 {
let inset: UIEdgeInsets? = (collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset
return inset!
}
let rightInset: CGFloat = leftInset
let sectionInset = UIEdgeInsets(top: 0, left: Float(leftInset), bottom: 0, right: Float(rightInset))
return sectionInset
}
![Untitled-3.png]()
Ответ 18
я пробовал много решений отсюда, но в конце дня самое простое решение работает лучше всего
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: YOUR HEIGHT)
}
ps без вставок в конструкторе интерфейсов
Ответ 19
Мне кажется, вам нужно центрировать ячейку, поэтому вместо использования коллекцииView я бы хотел, чтобы UITableView был очень полезен. Просто используйте UIViewController и поместите два UIView спереди и сзади и поместите UITableView
в середине
Надеюсь, что это поможет