UICollectionView 셀을 수평으로 중앙에 배치하는 방법은 무엇입니까?
몇 가지 조사를 했지만 UICollectionView에서 셀을 수평으로 중앙에 배치하는 방법에 대한 코드 예제를 찾을 수 없었습니다.
첫 번째 셀이 이 X00처럼 되는 대신, 저는 0X0처럼 되기를 원합니다. 이것을 달성할 방법이 있습니까?
편집:
내가 원하는 것을 시각화하는 것:
컬렉션 뷰에 요소가 하나만 있을 때 버전 B처럼 보여야 합니다.제가 두 개 이상의 요소를 얻었을 때, 버전 A와 비슷해야 하지만 더 많은 요소가 있어야 합니다.
현재는 요소가 하나밖에 없는데 버전 A처럼 보이는데 어떻게 하면 B처럼 만들 수 있는지 궁금합니다.
도와주셔서 감사합니다!
중앙 정렬만 목적으로 하는 경우에는 라이브러리를 사용하는 것이 좋지 않습니다.
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)
}
스위프트 5.1
func centerItemsInCollectionView(cellWidth: Double, numberOfItems: Double, spaceBetweenCell: Double, collectionView: UICollectionView) -> UIEdgeInsets {
let totalWidth = cellWidth * numberOfItems
let totalSpacingWidth = spaceBetweenCell * (numberOfItems - 1)
let leftInset = (collectionView.frame.width - CGFloat(totalWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
스위프트 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
스위프트 4용으로 사용해 보십시오.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let cellWidth : CGFloat = 165.0
let numberOfCells = floor(collectionView.frame.size.width / cellWidth)
let edgeInsets = (collectionView.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)
return UIEdgeInsetsMake(15, edgeInsets, 0, edgeInsets)
}
165.0 대신 cellWidth 추가
KT CenterFlowLayout을 사용하고 있습니다. 잘 작동합니다.의 사용자 지정 하위 클래스입니다.UICollectionViewFlowLayout
원하는 대로 셀을 중앙에 배치합니다. (참고: 이것은 코드를 게시하여 해결하는 사소한 문제가 아닙니다. 그래서 저는 GitHub 프로젝트에 링크하고 있습니다!)
- (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;
}
이 확장(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)
}
}
도움이 되길 바랍니다!
너비보다 작은 경우 페이지의 중심을 맞추고 더 많은 경우 왼쪽으로 정렬하는 흐름 레이아웃에 대한 일반 솔루션
- (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;
}
빠른 버전(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
}
@Safad Funy의 답변을 약간 수정하면, 이것이 제가 스위프트 & iOS의 최신 버전에서 작동한 것입니다.이 경우 셀의 너비가 컬렉션 보기 크기의 3분의 1이 되기를 원했습니다.
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)
}
다음은 Swift 5의 최신 버전으로, 셀이 두 개 이상의 행에 있을 때도 작동합니다.
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
var cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
var collectionWidth = collectionView.frame.size.width
var totalWidth: CGFloat
if #available(iOS 11.0, *) {
collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
}
repeat {
totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
cellCount -= 1
} while totalWidth >= collectionWidth
if (totalWidth > 0) {
let edgeInset = (collectionWidth - totalWidth) / 2
return UIEdgeInsets.init(top: flowLayout.sectionInset.top, left: edgeInset, bottom: flowLayout.sectionInset.bottom, right: edgeInset)
} else {
return flowLayout.sectionInset
}
}
수업이 다음을 준수하는지 확인하십시오.UICollectionViewDelegateFlowLayout
의전
Swift 4.2(수평 및 수직).그것은 핑크 팬서 코드의 작은 업그레이드이고 그에게 큰 감사를 드립니다!
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 프로토콜을 준수하는지 확인합니다.
스위프트 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)
}
}
패딩만 추가하려는 사용자(위, 왼쪽, 아래, 오른쪽):
UICollectionViewDelegateFlowLayout
이 예에서는 40개의 왼쪽과 오른쪽 패딩을 보여 줍니다.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 40, 0, 40)
}
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)
}
}
Darshan Patel의 답변을 사용하는 경우 UICollectionViewFlowLayout 하위 클래스 내에서 계산을 수행할 수도 있습니다.
class Layout: UICollectionViewFlowLayout {
override init() {
super.init()
scrollDirection = .horizontal
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError()
}
override func prepare() {
super.prepare()
guard let collectionView = collectionView,
collectionView.numberOfSections != 0 else { return }
minimumInteritemSpacing = 5
itemSize = CGSize(width: 30, height: 30)
sectionInsetReference = .fromSafeArea
let numberOfItems = collectionView.numberOfItems(inSection: 0)
let totalCellWidth = itemSize.width * CGFloat(numberOfItems)
let totalSpacingWidth = minimumInteritemSpacing * CGFloat(numberOfItems - 1)
let leftInset = (collectionView.bounds.maxX - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
sectionInset = UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: leftInset)
}
}
셀이 화면 너비에 맞지 않을 때 문제를 해결하는 현재 허용된 답변의 빠른 5 수정.
교체해야 합니다.cellWidth
그리고.cellSpacing
사용자 정의 값을 사용할 수 있습니다.
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
let cellCount = collectionView.numberOfItems(inSection: section)
let totalCellWidth = cellWidth * CGFloat(cellCount)
let totalSpacingWidth = cellSpacing * CGFloat(cellCount - 1)
let collectionViewInset = collectionView.contentInset.left + collectionView.contentInset.right
let inset = (collectionView.frame.width - collectionViewInset - totalCellWidth - totalSpacingWidth) / 2
return inset > 0
? UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset)
: UIEdgeInsets.zero
}
제 해결책을 시도해 보세요. 잘 작동합니다.
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)
}
받아들여진 답이 맞는 답이지만 만약 당신이totalCellWidth
다니작보다 .CollectionView
의width
그러나 이를 방지하기 위해 아래와 같이 할 수 있습니다.
if (leftInset > 0) {
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
} else {
return UIEdgeInsetsMake(0, 10, 0, 10)
}
이 코드는 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
만약 그룹당 하나의 셀만을 위한 공간이 있다면,leading:
그리고.trailing:
.flexible(0)
셀의 중심을 수평으로 맞춥니다.
item.edgeSpacing = NSCollectionLayoutEdgeSpacing(
leading: .flexible(0), top: nil,
trailing: .flexible(0), bottom: nil
)
저는 여기서 완전히 다른 접근법을 택하게 되었습니다. 언급할 가치가 있다고 생각합니다.
컬렉션 뷰가 중앙에 수평으로 정렬되도록 제약 조건을 설정했습니다.그런 다음 너비를 지정하는 다른 제약 조건을 설정합니다.내 뷰 내부에 집합 뷰를 보유하는 컨트롤러의 너비 제약 조건에 대한 배출구를 만들었습니다.그런 다음 데이터 원본이 변경되고 수집 보기를 업데이트할 때 셀 수를 계산하여 폭을 재설정합니다.
let newWidth = (items.count * cellWidth) + (items.count * cellSpacing)
그런 다음 제약 조건 콘센트를 설정합니다..constant
값은 계산 결과에 적용되고 자동 레이아웃은 나머지를 수행합니다.
이는 'UICollectionViewDelegateFlowLayout'과 충돌할 수 있지만 왼쪽 맞춤 컬렉션 뷰를 만드는 데는 완벽하게 효과적이었습니다.대리인이 없으면 셀이 뷰의 대부분을 채웠을 때만 작동하는 것 같습니다.
저는 프로젝트에서 비슷한 상황을 가지고 있으며, 참고하여 수정하였습니다.
버전을 지원하는 것 같습니다.
의 코드 구현을 확인하십시오.
override open func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint
가장 간단한 방법은 스토리보드 또는 코드에서 컬렉션 뷰 추정 크기를 없음으로 설정하는 것입니다.layout.estimatedItemSize = CGSize.zero
저는 그 코드를 프로젝트에 사용했습니다.컬렉션의 중심을 맞춥니다.양방향으로 수평 및 수직으로 보기.horizontal
그리고..vertical
섹션의 삽입을 사용합니다.설정된 경우 섹션의 간격과 원래 삽입값을 준수합니다.딜러에서 사용할 코드UICollectionViewDelegateFlowLayout
그래서 우리는 우리가 검색해야 하는 모든 속성에 접근할 수 있습니다.UIcollectionView
또는 재사용 가능성을 위해 스토리보드에 설정합니다.
// original function of the delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
// casting the layout as a UICollectionViewFlowLayout to have access to the properties of items for reusability - you could also link the real one from the storyboard with an outlet
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
// getting all the properties we need
let itemWidth = flowLayout.itemSize.width
let itemHeight = flowLayout.itemSize.height
let interSpacing = flowLayout.minimumInteritemSpacing
let lineSpacing = flowLayout.minimumLineSpacing
// getting the size of the collectionView
let collectionWidth = collectionView.bounds.width
let collectionHeight = collectionView.bounds.height
// getting the direction to choose how to align the collection
let direction = flowLayout.scrollDirection
// you don't want to have an item greater than the collection
guard (itemWidth < collectionWidth && direction == .vertical) || (itemHeight < collectionHeight && direction == .horizontal) else {
print("Really?")
return UIEdgeInsets(top: flowLayout.sectionInset.top, left: flowLayout.sectionInset.left, bottom: flowLayout.sectionInset.bottom, right: flowLayout.sectionInset.right)
}
// getting the number of item in the current section
let totalItemCount = CGFloat(collectionView.numberOfItems(inSection: section))
// setting number of item in a row to the max number of items that can fit in a row without spacing or to the number of items in the section if less than the max
var itemCountInRow = totalItemCount < (collectionWidth / itemWidth).rounded(.towardZero) ? totalItemCount : (collectionWidth / itemWidth).rounded(.towardZero)
// how many max row can we have
var countOfRow = totalItemCount < (collectionHeight / itemHeight).rounded(.towardZero) ? totalItemCount : (collectionHeight / itemHeight).rounded(.towardZero)
// calculating the total width of row by multiplying the number of items in the row by the width of item and adding the spacing multiplied by the number of item minus one
var totalWidthOfRow:CGFloat {
get{
return (itemWidth * itemCountInRow) + (interSpacing * (itemCountInRow - 1))
}
}
// calculating the total height of row by multiplying the number of row by the height of item and adding the spacing multiplied by the number of row minus one
var totalHeightOfRow:CGFloat {
get{
return (itemHeight * countOfRow) + (lineSpacing * (countOfRow - 1))
}
}
// first we set the inset to the default
var edgeInsetLeft = flowLayout.sectionInset.left
var edgeInsetTop = flowLayout.sectionInset.top
if direction == .vertical {
// while the width of row with original margin is greater than the width of the collection we drop one item until it fits
while totalWidthOfRow > collectionWidth || ((collectionWidth - totalWidthOfRow) / 2) < flowLayout.sectionInset.left {
// droping an item to fit in the row
itemCountInRow -= 1
}
// calculating the number of rows in collectionView by dividing the number of items by the number of items in a row
countOfRow = (totalItemCount / (itemCountInRow)).rounded(.up)
} else {
itemCountInRow = (totalItemCount / countOfRow).rounded(.up)
// while the height of row with original marginis greater than the height of the collection we drop one row until it fits
while totalHeightOfRow >= collectionHeight || ((collectionHeight - totalHeightOfRow) / 2) < flowLayout.sectionInset.top {
// droping an item to fit in the row
countOfRow -= 1
}
}
edgeInsetLeft = max(flowLayout.sectionInset.left, (collectionWidth - totalWidthOfRow) / 2)
edgeInsetTop = max(flowLayout.sectionInset.top, (collectionHeight - totalHeightOfRow) / 2)
// we don't specially need insets where the items are overflowing
let edgeInsetRight = direction == .vertical ? edgeInsetLeft : flowLayout.sectionInset.right
let edgeInsetBottom = direction == .horizontal ? edgeInsetTop : flowLayout.sectionInset.bottom
// returning the UIEdgeInsets
return UIEdgeInsets(top: edgeInsetTop, left: edgeInsetLeft, bottom: edgeInsetBottom, right: edgeInsetRight)
}
누군가에게 도움이 되기를 바랍니다. 섹션 내부의 항목이 아니라 섹션을 중심으로 합니다. 더 많은 것을 하위 분류해야 합니다.UICollectionViewFlowLayout
또는UICollectionViewLayout
애플의 모자이크 예시로서.
데이터가 더 많을 때 위의 답변에서 한 가지 개선된 점이 있습니다. 다음 코드를 사용하십시오.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
var totalCellsWidth:CGFloat = 0
for index in 0..<numberOfCells{
let width = viewModel.getCellWidth(at: index) // get cell width is to dynamically calculate the width of the cell according to the text
totalCellsWidth += width
}
let cellSpacing:CGFloat = 8.0
let totalSpacingWidth = cellSpacing * CGFloat(viewModel.teamsCount - 1)
var leftInset = (collectionView.frame.width - (totalCellsWidth + totalSpacingWidth)) / 2
if leftInset < 0{
leftInset = 0
}
let rightInset = leftInset
return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
여기서 사용자 정의 UICollectionViewFlowLayout을 다음과 같이 정의해야 합니다.
class CenterAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let superArray = super.layoutAttributesForElements(in: rect) else { return nil }
guard let attributes = NSArray(array: superArray, copyItems: true) as? [UICollectionViewLayoutAttributes] else { return nil }
// Constants
let leftPadding: CGFloat = 8
let interItemSpacing = minimumInteritemSpacing
// Tracking values
var leftMargin: CGFloat = leftPadding // Modified to determine origin.x for each item
var maxY: CGFloat = -1.0 // Modified to determine origin.y for each item
var rowSizes: [[CGFloat]] = [] // Tracks the starting and ending x-values for the first and last item in the row
var currentRow: Int = 0 // Tracks the current row
attributes.forEach { layoutAttribute in
// Each layoutAttribute represents its own item
if layoutAttribute.frame.origin.y >= maxY {
// This layoutAttribute represents the left-most item in the row
leftMargin = leftPadding
// Register its origin.x in rowSizes for use later
if rowSizes.count == 0 {
// Add to first row
rowSizes = [[leftMargin, 0]]
} else {
// Append a new row
rowSizes.append([leftMargin, 0])
currentRow += 1
}
}
layoutAttribute.frame.origin.x = leftMargin
leftMargin += layoutAttribute.frame.width + interItemSpacing
maxY = max(layoutAttribute.frame.maxY, maxY)
// Add right-most x value for last item in the row
rowSizes[currentRow][1] = leftMargin - interItemSpacing
}
// At this point, all cells are left aligned
// Reset tracking values and add extra left padding to center align entire row
leftMargin = leftPadding
maxY = -1.0
currentRow = 0
attributes.forEach { layoutAttribute in
// Each layoutAttribute is its own item
if layoutAttribute.frame.origin.y >= maxY {
// This layoutAttribute represents the left-most item in the row
leftMargin = leftPadding
// Need to bump it up by an appended margin
let rowWidth = rowSizes[currentRow][1] - rowSizes[currentRow][0] // last.x - first.x
let appendedMargin = (collectionView!.frame.width - leftPadding - rowWidth - leftPadding) / 2
leftMargin += appendedMargin
currentRow += 1
}
layoutAttribute.frame.origin.x = leftMargin
leftMargin += layoutAttribute.frame.width + interItemSpacing
maxY = max(layoutAttribute.frame.maxY, maxY)
}
return attributes
}
}
그런 다음 컨트롤러의 뷰DidLoad 또는 관련 메서드에 다음을 추가합니다.
let layout = CenterAlignedCollectionViewFlowLayout()
layout.estimatedItemSize = CGSize(width: 200, height: 40)
self.collectionRateCustomer.collectionViewLayout = layout
UICollectionViewDelegateFlowLayout을 상속하는 것을 잊지 마십시오.
레퍼런스, equaleyes.com 및 알렉스 코시의 답변
다른 접근법은 당신이 가지고 있는 공간을 당신이 표시하고 싶은 셀의 수로 나누는 것입니다, 이 방법은 당신이 모방할 것입니다.stackViews의 동일 모드 채우기
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width / CGFloat(collectionView.numberOfItems(inSection: indexPath.section)), height: 28)
}
잊지 말고 다음을 하라:
- 셀 내용 보기의 보기를 후행 및 선행 제약 조건 없이 컨테이너 중앙에 고정된 너비로 설정
- CollectionView의 Inspector(검사기)에서 셀 및 선에 대한 최소 간격을 제거하고 각각 0으로 설정합니다.
- 위의 코드 조각에 높이를 제공합니다. 지금처럼 28이 아니라
여러 행에서 이 작업은 효과가 있었습니다.
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
let cellWidth = 370
let cellSpaceing = 10
let totalCellWithSpace = cellWidth + cellSpaceing
let howManyCellsInRow = Int(Int(collectionView.layer.frame.size.width) / (totalCellWithSpace))
let inset = (collectionView.layer.frame.size.width - CGFloat(howManyCellsInRow * totalCellWithSpace)) / 2
return UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset)
}
저는 동일한 문제를 해결하기 위해 이 프로젝트에서 레이아웃을 복사하여 UICollectionViewFlowLayout으로 적용했습니다.전체 라이브러리를 적용할 필요 없이 레이아웃 클래스만 복사하면 됩니다.
https://github.com/Coeur/CollectionViewCenteredFlowLayout
집합별로 설정합니다.내용 크기 보기.아래에서 나는 텍스트 길이에 따른 셀 너비를 사용했습니다.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let font = FontNames.mediumFont12
let fontAttributes = [NSAttributedString.Key.font: font]
let text = "Your text"
let size = (text as NSString).size(withAttributes: fontAttributes)
self.setInsets(width: self.tagsCollectionView.contentSize.width)
return CGSize(width: size.width+30.0, height: self.tagsCollectionView.bounds.height)
}
func setInsets(width: CGFloat) {
let inset = self.tagsCollectionView.bounds.width - width
if inset <= 26.0 {
self.tagsCollectionView.contentInset = UIEdgeInsets(top: 0.0, left: 26.0, bottom: 0.0, right: 26.0)
} else {
self.tagsCollectionView.contentInset = UIEdgeInsets(top: 0.0, left: inset/2.0, bottom: 0.0, right: inset/2.0)
}
}
셀 너비 및 내부 패딩 변경
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let cellWidth : CGFloat = 100
let paddingInside: CGFloat = 10
let numberOfCells = floor(collectionView.frame.size.width / cellWidth)
let edgeInsets = (collectionView.frame.size.width - (numberOfCells * cellWidth)) / 2 - paddingInside
return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: edgeInsets)
}
그리고 VC를 UICollectionViewDelegateFlowLayout 프로토콜로 확인하는 것을 잊지 마십시오.
언급URL : https://stackoverflow.com/questions/34267662/how-to-center-horizontally-uicollectionview-cells
'programing' 카테고리의 다른 글
각도를 사용하여 새 탭에서 링크를 여는 방법은 무엇입니까? (0) | 2023.05.02 |
---|---|
Windows에서 SSH에서 Vagrant 박스로? (0) | 2023.04.27 |
MVVM 템플릿의 좋은 예 (0) | 2023.04.27 |
등호(=) 대맘에 들다 (0) | 2023.04.27 |
zure의 윈도우 서비스와 동등한 것은 무엇입니까? (0) | 2023.04.27 |