[ios] UICollectionView의 셀을 가운데 정렬하는 방법은 무엇입니까?

현재 UICollectionView사용자 인터페이스 그리드를 사용하고 있으며 제대로 작동합니다. 그러나 가로 스크롤을 사용하고 싶습니다. 그리드는 페이지 당 8 개 항목을 지원하며 총 항목 수가 4 개일 때 가로 스크롤 방향이 활성화 된 상태에서 항목을 정렬하는 방법은 다음과 같습니다.

0 0 x x
0 0 x x

여기에 0-> 컬렉션 항목 및 x-> 빈 셀

다음과 같이 가운데 정렬하는 방법이 있습니까?

x 0 0 x
x 0 0 x

콘텐츠가 더 깔끔하게 보이도록?

또한 아래 배열이 내가 기대하는 해결책이 될 수도 있습니다.

0 0 0 0
x x x x



답변

다음과 같이 구현하면 한 줄 모양을 얻을 수 있다고 생각합니다.

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 100, 0, 0);
}

콘텐츠를 한 줄로 만드는 방법을 알아 내려면 해당 번호를 가지고 놀아야합니다. 첫 번째 0은 상단 가장자리 인수입니다. 화면에서 콘텐츠를 세로로 중앙에 배치하려면이 인수도 조정할 수 있습니다.


답변

중앙 정렬, 동적 너비 collectionview 셀 에 대한 솔루션을 찾는 사람들을 위해 왼쪽 정렬 버전 에 대한 Angel의 대답을 수정하여 UICollectionViewFlowLayout.

CenterAlignedCollectionViewFlowLayout

// NOTE: Doesn't work for horizontal layout!
class CenterAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let superAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
        // Copy each item to prevent "UICollectionViewFlowLayout has cached frame mismatch" warning
        guard let attributes = NSArray(array: superAttributes, 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
    }
}

CenterAlignedCollectionViewFlowLayout


답변

여기에있는 최고의 솔루션은 기본적으로 작동하지 않았으므로 흐름 레이아웃과 하나의 섹션 만있는 가로 스크롤 컬렉션보기에서 작동해야하는 이것을 생각해 냈습니다.

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
    {
    // Add inset to the collection view if there are not enough cells to fill the width.
    CGFloat cellSpacing = ((UICollectionViewFlowLayout *) collectionViewLayout).minimumLineSpacing;
    CGFloat cellWidth = ((UICollectionViewFlowLayout *) collectionViewLayout).itemSize.width;
    NSInteger cellCount = [collectionView numberOfItemsInSection:section];
    CGFloat inset = (collectionView.bounds.size.width - (cellCount * cellWidth) - ((cellCount - 1)*cellSpacing)) * 0.5;
    inset = MAX(inset, 0.0);
    return UIEdgeInsetsMake(0.0, inset, 0.0, 0.0);
    }


답변

인세 트를 동적으로 계산하는 것은 쉽습니다.이 코드는 항상 셀을 중앙에 배치합니다.

NSInteger const SMEPGiPadViewControllerCellWidth = 332;

...

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{

    NSInteger numberOfCells = self.view.frame.size.width / SMEPGiPadViewControllerCellWidth;
    NSInteger edgeInsets = (self.view.frame.size.width - (numberOfCells * SMEPGiPadViewControllerCellWidth)) / (numberOfCells + 1);

    return UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets);
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.collectionView.collectionViewLayout invalidateLayout];
}


답변

다른 답변과 마찬가지로 이것은 정적 크기의 셀에서 작동해야하는 동적 답변입니다. 내가 만든 한 가지 수정 사항은 패딩을 양쪽에 넣는 것입니다. 이렇게하지 않으면 문제가 발생했습니다.


목표 -C

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {

    NSInteger numberOfItems = [collectionView numberOfItemsInSection:section];
    CGFloat combinedItemWidth = (numberOfItems * collectionViewLayout.itemSize.width) + ((numberOfItems - 1) * collectionViewLayout.minimumInteritemSpacing);
    CGFloat padding = (collectionView.frame.size.width - combinedItemWidth) / 2;

    return UIEdgeInsetsMake(0, padding, 0, padding);
}

빠른

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let numberOfItems = CGFloat(collectionView.numberOfItems(inSection: section))
    let combinedItemWidth = (numberOfItems * flowLayout.itemSize.width) + ((numberOfItems - 1)  * flowLayout.minimumInteritemSpacing)
    let padding = (collectionView.frame.width - combinedItemWidth) / 2
    return UIEdgeInsets(top: 0, left: padding, bottom: 0, right: padding)
}

또한 여전히 문제가 발생하는 경우 이러한 값이 서로 관련되어있는 것처럼 보이기 때문에 minimumInteritemSpacing및 모두 minimumLineSpacing동일한 값으로 설정해야합니다 .

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
flowLayout.minimumInteritemSpacing = 20.0;
flowLayout.minimumLineSpacing = 20.0;


답변

이것을 컬렉션 뷰 델리게이트에 넣으십시오. 다른 답변보다 기본 흐름 레이아웃 설정을 더 많이 고려하므로 더 일반적입니다.

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    NSInteger cellCount = [collectionView.dataSource collectionView:collectionView numberOfItemsInSection:section];
    if( cellCount >0 )
    {
        CGFloat cellWidth = ((UICollectionViewFlowLayout*)collectionViewLayout).itemSize.width+((UICollectionViewFlowLayout*)collectionViewLayout).minimumInteritemSpacing;
        CGFloat totalCellWidth = cellWidth*cellCount + spacing*(cellCount-1);
        CGFloat contentWidth = collectionView.frame.size.width-collectionView.contentInset.left-collectionView.contentInset.right;
        if( totalCellWidth<contentWidth )
        {
            CGFloat padding = (contentWidth - totalCellWidth) / 2.0;
            return UIEdgeInsetsMake(0, padding, 0, padding);
        }
    }
    return UIEdgeInsetsZero;
}

신속한 버전 (g0ld2k에게 감사) :

extension CommunityConnectViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    // Translated from Objective-C version at: http://stackoverflow.com/a/27656363/309736

        let cellCount = CGFloat(viewModel.getNumOfItemsInSection(0))

        if cellCount > 0 {
            let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
            let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing
            let totalCellWidth = cellWidth*cellCount + spacing*(cellCount-1)
            let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right

            if (totalCellWidth < contentWidth) {
                let padding = (contentWidth - totalCellWidth) / 2.0
                return UIEdgeInsetsMake(0, padding, 0, padding)
            }
        }

        return UIEdgeInsetsZero
    }
}


답변

왼쪽과 오른쪽에 패딩이 필요한 정적 크기의 컬렉션 뷰 셀에 대한 내 솔루션-

func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    let flowLayout = (collectionViewLayout as! UICollectionViewFlowLayout)
    let cellSpacing = flowLayout.minimumInteritemSpacing
    let cellWidth = flowLayout.itemSize.width
    let cellCount = CGFloat(collectionView.numberOfItemsInSection(section))

    let collectionViewWidth = collectionView.bounds.size.width

    let totalCellWidth = cellCount * cellWidth
    let totalCellSpacing = cellSpacing * (cellCount - 1)

    let totalCellsWidth = totalCellWidth + totalCellSpacing

    let edgeInsets = (collectionViewWidth - totalCellsWidth) / 2.0

    return edgeInsets > 0 ? UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets) : UIEdgeInsetsMake(0, cellSpacing, 0, cellSpacing)
}