Làm thế nào để căn giữa các ô UICollectionView theo chiều ngang?


123

Tôi đã thực hiện một số nghiên cứu, nhưng tôi không thể tìm thấy bất kỳ ví dụ mã nào về cách căn giữa các ô trong UICollectionView theo chiều ngang.

thay vì ô đầu tiên giống như X00 này , tôi muốn nó giống như 0X0 này . Có cách nào để thực hiện điều này?

BIÊN TẬP:

để hình dung những gì tôi muốn:

nhập mô tả hình ảnh ở đây

Tôi cần nó giống như phiên bản B khi chỉ có một phần tử trong CollectionView. Khi tôi có nhiều hơn một phần tử, thì nó sẽ giống như phiên bản A nhưng có nhiều phần tử hơn.

Hiện tại, nó trông giống như Phiên bản A khi tôi chỉ có 1 phần tử và tôi tự hỏi làm thế nào tôi có thể làm cho nó giống Phiên bản B.

Cảm ơn đã giúp đỡ!


Không phải dễ dàng hơn để để ô vừa với chiều rộng của chế độ xem bộ sưu tập và sau đó căn giữa chính chế độ xem bộ sưu tập bên trong chính nó?
Arthur Gevorkyan

vâng, có ít nhất hai cách để làm điều này, đầu tiên (nhanh) là tạo chiều rộng ô của toàn màn hình và căn giữa chế độ xem con của nó. thứ hai (bên phải) thực hiện tùy chỉnh bố trí xem bộ sưu tập
sage444

Sẽ có cuối cùng hơn tế bào đến từ backend, lấp đầy toàn bộ chiều rộng sẽ không phải là một ý tưởng tốt
RaptoX

tăng chiều rộng là đủ để đặt ở trung tâm
Kishore Kumar

Câu trả lời:


227

Không nên sử dụng thư viện, nếu mục đích của bạn chỉ là điều này, tức là căn giữa.

Tốt hơn bạn có thể thực hiện phép tính đơn giản này trong hàm collectionViewLayout của mình.

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
@ DarshanPatel. Cảm ơn rất nhiều câu trả lời mà tôi đã thực hiện điều này và các hàng đã ở chính giữa như bình thường nhưng bây giờ vấn đề là tôi không thể cuộn đến mục đầu tiên. Khi tôi cố gắng cuộn đến mục đầu tiên, nó sẽ đưa tôi trở lại UIEdgeInsets đã sửa đổi. Bạn có thể thấy ứng dụng demo của tôi github.com/anirudha-music/CollectionViewCenter
Anirudha Mahale

5
Trong Swift 3, chữ ký phương thức mới là collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int).
Kamchatka

1
làm thế nào bạn có thể lấy cellWidth, có thể thông qua phương thức cellForItemAt không? tôi đã thử và nó trả về nil .. chiều rộng ô đối với tôi thay đổi dựa trên kích thước màn hình .. @DarshanPatel.
Chris

10
@DarshanPatel. Câu trả lời của bạn đôi khi có thể tạo ra giá trị âm trên các thiết bị nhỏ hơn. Xem xét sử dụng một tấm séc tối đa trên bạn leftInsetđánh giá như sau:let leftInset = max(0.0, (self.collectionView.bounds.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2)
Rhuari Glen

3
Nếu bạn không phân lớp UICollectionViewController, hãy đảm bảo rằng lớp của bạn tuân theo UICollectionViewDelegateFlowLayout nếu không nó sẽ không hoạt động
Saeed Ir

59

Swift 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)
}

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)

}

Swift 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)

    }

đừng quên thêm giao thức

UICollectionViewDelegateFlowLayout

có thể ràng buộc @ashForIos
Ahmed Safadi

Câu trả lời của bạn hoạt động tốt khi có các ô vừa với bộ sưu tậpXem khi số lượng ô tăng lên các ô nằm ở giữa và bạn không thể cuộn đến ô đầu tiên hoặc ô cuối cùng.
NickCoder

2
@Vitalii 80 có nghĩa là Chiều rộng ô và 10 khoảng cách giữa các ô, nếu bạn đọc tên biến, bạn sẽ hiểu nó có nghĩa là gì: P
Ahmed Safadi

Giải pháp Swift 4.2 dễ dàng hơn, CẢM ƠN! Chỉ cần đảm bảo đặt "80" thành bất kỳ chiều rộng đối tượng ô thực tế của bạn.
John Pitts

25

Hãy thử cái này cho 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)
    }

Thêm chiều rộng ô của bạn thay vì 165.0


1
đây là câu trả lời tốt nhất. Với phép toán đơn giản nhất vào nó. hoạt động với bất kỳ số hàng và cột nào
rickrvo

20

Tôi sử dụng KTCenterFlowLayout cho việc này, và nó hoạt động rất tốt. Đó là một lớp con tùy chỉnh của UICollectionViewFlowLayoutcác ô căn giữa như bạn muốn. (Lưu ý: đây không phải là một việc tầm thường để giải quyết bằng cách đăng một số mã, đó là lý do tại sao tôi liên kết với một dự án GitHub!)


Không thể làm cho nó hoạt động từ IB. Thư viện này hoạt động như một cái duyên đối với tôi. Chỉ cần cài đặt pod và thay đổi lớp bố cục trong IB!
tagirkaZ

15

Một phiên bản mục tiêu-C của câu trả lời của 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;
}

cảm ơn. Nó hoạt động tốt với một hàng. nhưng tạo ra vấn đề trong nhiều hàng. Tôi không thể thêm url vào đây để hiển thị ảnh chụp màn hình u. . nhưng bạn có thể thêm "yynoalzg" trong url nhỏ. bạn sẽ có ý tưởng. Phần vàng có 4 kỷ lục. Thứ 4 nên ở dòng mới. .nhưng sau phương pháp này nó hiển thị như vậy ... hãy cho tôi biết nếu có ý tưởng.
Hitarth

6

Sửa đổi một chút câu trả lời của @Safad Funy, đây là điều phù hợp với tôi trong phiên bản Swift & iOS chậm nhất. Trong trường hợp này, tôi muốn chiều rộng của các ô bằng một phần ba kích thước của chế độ xem bộ sưu tập.

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

2
Điều này đặc biệt hiệu quả đối với tôi, khi chỉ có một ô.
Dasoga

6

Bạn có thể sử dụng tiện ích mở rộng này (Swift 4).

Nó có thể căn giữa các ô nếu bạn collectionViewlayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize .

Nó hoạt động với bất kỳ kích thước ô nào và hoạt động hoàn hảo khi 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)
    }
}

Hy vọng nó sẽ giúp bạn!


1
Bắt lỗi: Chủ đề 1: EXC_BAD_ACCESS (mã = 2, địa chỉ = 0x118ffde58)
atulkhatri

4

Swift 4.2 (Theo chiều ngang và chiều dọc). Đó là bản nâng cấp nhỏ của mã Pink Panther và rất cảm ơn anh ấy!


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)

    }
}

Đảm bảo lớp của bạn tuân theo giao thức UICollectionViewDelegateFlowLayout


Thực sự mã của bạn làm việc tuyệt vời cho tôi, cảm ơn Dude; )
steveSarsawa

4

Đây là phiên bản mới hơn cho Swift 5 cũng hoạt động tốt khi các ô có nhiều hơn một hàng:

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

Hãy đảm bảo rằng lớp của bạn tuân theo UICollectionViewDelegateFlowLayoutgiao thức.


3

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

 }

2

Đối với những người chỉ muốn thêm khoảng đệm ( trên, trái, dưới, phải ):

Thêm giao thức UICollectionViewDelegateFlowLayout

Ví dụ này cho thấy một phần đệm bên trái và bên phải với 40.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {        
    return UIEdgeInsetsMake(0, 40, 0, 40)
}

2

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

1

Bạn có thể thử giải pháp của tôi, nó hoạt động tốt,

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

1

Câu trả lời được chấp nhận là câu trả lời đúng nhưng nếu của bạn totalCellWidthnhỏ hơn CollectionViewcủa width, nhưng chỉ để đề phòng điều này, bạn có thể làm như dưới đây.

if (leftInset > 0) {
     return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
  } else {
     return UIEdgeInsetsMake(0, 10, 0, 10)
}

1

Mã này phải căn giữa chế độ xem thu thập theo chiều ngang ngay cả trong Swift 4.0 mà không có bất kỳ sửa đổi nào:

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

Đảm bảo lớp của bạn tuân theo UICollectionViewDelegateFlowLayoutgiao thức


0

Cuối cùng, tôi đã thực hiện một cách tiếp cận hoàn toàn khác ở đây, mà tôi tin rằng nó đáng được đề cập.

Tôi đặt một giới hạn cho chế độ xem bộ sưu tập của mình để được căn chỉnh theo chiều ngang ở trung tâm. Sau đó, tôi thiết lập một ràng buộc khác chỉ định chiều rộng. Tôi đã tạo một lối thoát cho giới hạn chiều rộng bên trong viewController của tôi để chứa chế độ xem bộ sưu tập. Sau đó, khi nguồn dữ liệu của tôi bị thay đổi và tôi đang cập nhật chế độ xem bộ sưu tập, tôi lấy số lượng ô và thực hiện một phép tính (rất giống) để đặt lại chiều rộng.

let newWidth = (items.count * cellWidth) + (items.count * cellSpacing)

Sau đó, tôi đặt .constantgiá trị của đầu ra ràng buộc thành kết quả tính toán và tự động thanh toán thực hiện phần còn lại.

Điều này có thể xung đột với `UICollectionViewDelegateFlowLayout, nhưng điều này đã hoạt động hoàn hảo để tôi tạo chế độ xem bộ sưu tập căn trái. Không có đại biểu, nó chỉ có vẻ hoạt động khi các ô lấp đầy phần lớn chế độ xem.


0

Giải pháp chung cho quy trình phân luồng căn giữa các trang nếu chúng nhỏ hơn chiều rộng và căn trái nếu có nhiều hơn

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

Phiên bản Swift (được chuyển đổi từ 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
}

Không có tiêu đề-3.png


Giới hạn trong mã nhanh là gì? lỗi tôi đang nhận được sử dụng định danh chưa được giải quyết 'giới hạn'
Sachin Tanpure

Hi, trong ví dụ của tôi, tôi đã áp dụng bên trong một UIView, trong đó có giới hạn, nếu bạn đang thực hiện nó ở nơi khác, sử dụng các giới hạn thích hợp
Peter Lapisu


0

cách đơn giản nhất là đặt kích thước ước tính của chế độ xem bộ sưu tập thành Không có trong bảng phân cảnh hoặc bằng mã layout.estimatedItemSize = CGSize.zero


0

Nếu chỉ có chỗ cho một ô cho mỗi nhóm, a leading:trailing:of .flexible(0)sẽ căn giữa ô theo chiều ngang:

item.edgeSpacing = NSCollectionLayoutEdgeSpacing(
    leading: .flexible(0), top: nil,                                                     
    trailing: .flexible(0), bottom: nil
)

0

Tôi đã sử dụng mã đó trong một dự án. Nó căn giữa collectionView theo chiều ngang và chiều dọc theo cả hai hướng .horizontal.verticalsử dụng các phần trong của phần. Tôn trọng khoảng cách và nội dung ban đầu của phần nếu được đặt. Mã để sử dụng trong ủy quyền UICollectionViewDelegateFlowLayoutđể chúng tôi có quyền truy cập vào tất cả các thuộc tính chúng tôi cần lấy từ UIcollectionViewhoặc bộ trong bảng phân cảnh để có thể sử dụng lại.

// 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)
}

Hy vọng nó sẽ giúp ích cho ai đó - nó tập trung phần không phải là các mục bên trong phần, để biết thêm, chúng tôi phải phân loại UICollectionViewFlowLayouthoặc UICollectionViewLayoutnhư ví dụ khảm từ Apple.


-4

Tôi nghĩ rằng bạn cần căn giữa ô, vì vậy thay vì sử dụng collectionView, tôi muốn UITableView sẽ rất hữu ích. Chỉ cần sử dụng một UIViewController và đặt hai UIView ở phía trước và phía sau và đặt UITableViewở giữa. Hy vọng điều này sẽ hữu ích


Tôi đã thêm một hình ảnh, để cho bạn thấy chính xác những gì tôi cần, cảm ơn!
RaptoX
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.