programing

UICollectionView 셀을 수평으로 중앙에 배치하는 방법은 무엇입니까?

bestprogram 2023. 4. 27. 22:54

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 프로젝트에 링크하고 있습니다!)

Darshan Patel의 답변의 목표 C 버전:

- (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
}

제목 없음-3.png

@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 다니작보다 .CollectionViewwidth그러나 이를 방지하기 위해 아래와 같이 할 수 있습니다.

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'과 충돌할 수 있지만 왼쪽 맞춤 컬렉션 뷰를 만드는 데는 완벽하게 효과적이었습니다.대리인이 없으면 셀이 뷰의 대부분을 채웠을 때만 작동하는 것 같습니다.

저는 프로젝트에서 비슷한 상황을 가지고 있으며, 참고하여 수정하였습니다.

버전을 지원하는 것 같습니다.

https://github.com/ink-spot/UPCarouselFlowLayout/blob/master/UPCarouselFlowLayout/UPCarouselFlowLayout.swift

의 코드 구현을 확인하십시오.

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