Répondez pour Objective-C
et Swift2.0
: Comment centrer les cellules d’un UICollectionView?
J'essayais généralement de convertir la réponse Swift2.0
à la solution Swift3.0
, mais la méthode:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
return UIEdgeInsetsMake(0, edgeInsets, 0, 0);
}
ne semble pas exister dans Swift3.0
, et la seule autre méthode que j'ai trouvée qui semble utile est:
func collectionView(_ collectionView: UICollectionView, transitionLayoutForOldLayout fromLayout: UICollectionViewLayout, newLayout toLayout: UICollectionViewLayout) -> UICollectionViewTransitionLayout {
<#code#>
}
mais je ne sais pas comment le mettre en œuvre correctement.
Comment centrer les cellules d'une UICollectionView
dans Swift3.0
?
(Une solution simple et générale pour iOS et tvOS serait parfaite)
Cela a fini par être la solution que j'ai utilisée. Lisez les commentaires du code pour une meilleure compréhension. Swift 3.0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
//Where elements_count is the count of all your items in that
//Collection view...
let cellCount = CGFloat(elements_count)
//If the cell count is zero, there is no point in calculating anything.
if cellCount > 0 {
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing
//20.00 was just extra spacing I wanted to add to my cell.
let totalCellWidth = cellWidth*cellCount + 20.00 * (cellCount-1)
let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right
if (totalCellWidth < contentWidth) {
//If the number of cells that exists take up less room than the
//collection view width... then there is an actual point to centering them.
//Calculate the right amount of padding to center the cells.
let padding = (contentWidth - totalCellWidth) / 2.0
return UIEdgeInsetsMake(0, padding, 0, padding)
} else {
//Pretty much if the number of cells that exist take up
//more room than the actual collectionView width, there is no
// point in trying to center them. So we leave the default behavior.
return UIEdgeInsetsMake(0, 40, 0, 40)
}
}
return UIEdgeInsets.zero
}
Alors que rottenoats answer est génial, il a un bug d’espacement supplémentaire et n’utilise pas beaucoup de la syntaxe Swift 3 disponible. J'ai corrigé cela et réduit le nombre de dépendances aux variables locales.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
// Make sure that the number of items is worth the computing effort.
guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout,
let dataSourceCount = collectionView.dataSource?.collectionView(collectionView, numberOfItemsInSection: section),
dataSourceCount > 0 else {
return .zero
}
let cellCount = CGFloat(dataSourceCount)
let itemSpacing = flowLayout.minimumInteritemSpacing
let cellWidth = flowLayout.itemSize.width + itemSpacing
var insets = flowLayout.sectionInset
// Make sure to remove the last item spacing or it will
// miscalculate the actual total width.
let totalCellWidth = (cellWidth * cellCount) - itemSpacing
let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right
// If the number of cells that exist take up less room than the
// collection view width, then center the content with the appropriate insets.
// Otherwise return the default layout inset.
guard totalCellWidth < contentWidth else {
return insets
}
// Calculate the right amount of padding to center the cells.
let padding = (contentWidth - totalCellWidth) / 2.0
insets.left = padding
insets.right = padding
return insets
}
NB: Cet extrait ne fonctionne que pour un défilement horizontal mais peut être facilement ajusté.
Légère adaptation de @rottenoats answer. Ceci est plus générique.
Surtout, n'oubliez pas de rendre votre contrôleur de vue conforme au protocole UICollectionViewDelegateFlowLayout.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout else {
return .zero
}
let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
if cellCount > 0 {
let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing
let totalCellWidth = cellWidth * cellCount
let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right - flowLayout.headerReferenceSize.width - flowLayout.footerReferenceSize.width
if (totalCellWidth < contentWidth) {
let padding = (contentWidth - totalCellWidth + flowLayout.minimumInteritemSpacing) / 2.0
return UIEdgeInsetsMake(0, padding, 0, 0)
}
}
return .zero
}
La méthode que vous recherchez est présente avec une signature différente dans Swift 3
. La nouvelle signature est la suivante:
optional public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
P.S: Cette méthode est présente dans le protocole UICollectionViewDelegateFlowLayout
.
J'espère que cela aiderait.
En supposant que vous vous conformez à UICollectionViewDelegateFlowLayout , il devrait être:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: 0)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let allCellWidth = KcellWidth * numberOfCell
let cellSpacingWidth = CellSpacing * (numberOfCell - 1)
let leftInset = (collectionViewWidth - CGFloat(allCellWidth + cellSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
Vous devez vous conformer au protocole UICollectionViewDelegateFlowLayout
pour trouver la méthode collectionView(_:layout:insetForSectionAt:)
; celle-ci y est définie. l'implémentation suivante fonctionne très bien dans Swift 4 pour une collection horizontale
extension YourViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let cellWidth = CGFloat(integerLiteral: YourCellsWidth)
let count = self.YourCollectionViewDataSource.count
let top = CGFloat(integerLiteral: 0) // I don't need to set top and bottom spacing
let cellsAccumulatedWidth = CGFloat(integerLiteral: count) * cellWidth
let cellsSpacingAccumulatedWidth = CGFloat(integerLiteral: (count - 1) * 5)
let left = (self.collectionView.frame.size.width - cellsAccumulatedWidth - cellsSpacingAccumulatedWidth) / 2
let bottom = top
let right = left
return UIEdgeInsetsMake(top, left, bottom, right);
}
}
Ce code doit centrer horizontalement tout type de vue de collection, même avec des éléments supplémentaires dans 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
}
}
N'oubliez pas que si vous ne sous-classez pas UICollectionViewController
, assurez-vous que votre classe est conforme au protocole UICollectionViewDelegateFlowLayout