Làm cách nào để đặt khoảng cách ô và tỷ lệ kích thước UICollectionView - UICollectionViewFlowLayout?


137

Tôi đang cố gắng thêm UICollectionViewvào ViewControllervà tôi cần có 3 ô 'mỗi hàng' mà không có khoảng trống giữa các ô (nó sẽ trông giống như một lưới). Chiều rộng ô phải bằng một phần ba kích thước màn hình, vì vậy tôi nghĩ rằng layout.itemchiều rộng phải giống nhau. Nhưng sau đó tôi nhận được điều này:

layout.itemSize width = screenSize. thong / 3

Nếu tôi giảm kích thước đó ( 7 hoặc 8 pixel, ví dụ), thì tốt hơn, nhưng ô thứ ba trong hàng không hoàn toàn hiển thị và tôi vẫn có khoảng trống đó (trên & dưới và trái & phải).

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

class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    var collectionView: UICollectionView?
    var screenSize: CGRect!
    var screenWidth: CGFloat!
    var screenHeight: CGFloat!

    override func viewDidLoad() {
        super.viewDidLoad()

        screenSize = UIScreen.mainScreen().bounds
        screenWidth = screenSize.width
        screenHeight = screenSize.height

        // Do any additional setup after loading the view, typically from a nib
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
        layout.itemSize = CGSize(width: screenWidth / 3, height: screenWidth / 3)
        collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collectionView!.dataSource = self
        collectionView!.delegate = self
        collectionView!.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
        collectionView!.backgroundColor = UIColor.greenColor()
        self.view.addSubview(collectionView!)
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 20
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as CollectionViewCell
        cell.backgroundColor = UIColor.whiteColor()
        cell.layer.borderColor = UIColor.blackColor().CGColor
        cell.layer.borderWidth = 0.5
        cell.frame.size.width = screenWidth / 3
        cell.frame.size.height = screenWidth / 3

        cell.textLabel?.text = "\(indexPath.section):\(indexPath.row)"
        return cell
    }
}

Đây là giải pháp của bạn. Cảm ơn.
janu kansagra

Dưới đây là Mã làm việc cho Swift 4 stackoverflow.com/a/54703798/10150796
Nikunj Kumbhani

Câu trả lời:


299

Thêm 2 dòng này

layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0

Vì vậy, bạn có:

   // Do any additional setup after loading the view, typically from a nib.
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
        layout.itemSize = CGSize(width: screenWidth/3, height: screenWidth/3)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        collectionView!.collectionViewLayout = layout

Điều đó sẽ loại bỏ tất cả các khoảng trắng và cung cấp cho bạn một bố cục lưới:

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

Nếu bạn muốn cột đầu tiên có chiều rộng bằng chiều rộng màn hình thì hãy thêm chức năng sau:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    if indexPath.row == 0
    {
        return CGSize(width: screenWidth, height: screenWidth/3)
    }
    return CGSize(width: screenWidth/3, height: screenWidth/3);

}

Bố cục lưới bây giờ sẽ trông như thế (Tôi cũng đã thêm nền màu xanh vào ô đầu tiên): nhập mô tả hình ảnh ở đây


Cảm ơn bạn rất nhiều, tôi đã mong đợi một cái gì đó phức tạp hơn nhiều, và tôi đã dành nhiều thời gian cho nó. Cảm ơn một lần nữa.
Marko

Và chỉ một điều nữa, có khả năng thay đổi layout.itemSize cho ô đầu tiên không? (Tôi biết rằng tôi cần thay đổi cell.frame.size khi indexPath.row bằng 0, nhưng không biết cách thay đổi kích thước bố cục chỉ cho một mục) Độ rộng phần tử đầu tiên phải bằng screenWidth .
Marko

1
Xin chào, tôi có cùng một vấn đề nhưng tôi muốn biết tiêu đề chức năng tương tự trong Mục tiêu C.
Nada Gamal

1
Ok, Nó hoạt động tốt bây giờ, Thanks a lot :) chức năng C Mục tiêu: - (CGSize) collectionView: (UICollectionView ) collectionView bố trí: (UICollectionViewLayout ) collectionViewLayout sizeForItemAtIndexPath: (NSIndexPath *) indexPath {return CGSizeMake (screenWidth / 3, screenWidth / 3 ); }
Nada Gamal

4
cảm ơn vì câu trả lời tuyệt vời @greentor. đã gửi một tiền thưởng. Đừng quên bộ sưu tậpView! .CollectionViewLayout = layout , độc giả
Fattie

46

Đối với Swift 3 và XCode 8 , điều này đã hoạt động. Thực hiện theo các bước dưới đây để đạt được điều này: -

{
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    let width = UIScreen.main.bounds.width
    layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    layout.itemSize = CGSize(width: width / 2, height: width / 2)
    layout.minimumInteritemSpacing = 0
    layout.minimumLineSpacing = 0
    collectionView!.collectionViewLayout = layout
}

Đặt mã này vào hàm viewDidLoad ().


32

Trong một số trường hợp nhất định, Đặt cài đặt UICollectionViewFlowLayouttrong viewDidLoadhoặc ViewWillAppearcó thể không ảnh hưởng đến bộ sưu tập.

Đặt UICollectionViewFlowLayoutin viewDidAppearcó thể gây ra thay đổi kích thước ô trong thời gian chạy.

Một giải pháp khác, trong Swift 3:

extension YourViewController : UICollectionViewDelegateFlowLayout{

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let collectionViewWidth = collectionView.bounds.width
        return CGSize(width: collectionViewWidth/3, height: collectionViewWidth/3)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 20
    }
}

Câu trả lời chính xác! Đây chắc chắn là cách của Apple để làm điều đó. Bây giờ, bạn không biết cách làm mới khi thiết bị thay đổi hướng, phải không?
jlstr

17

Nếu bạn đang tìm kiếm Swift 3, hãy làm theo các bước để đạt được điều này:

func viewDidLoad() {

    //Define Layout here
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()

    //Get device width
    let width = UIScreen.main.bounds.width

    //set section inset as per your requirement.
    layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)

    //set cell item size here 
    layout.itemSize = CGSize(width: width / 2, height: width / 2)

    //set Minimum spacing between 2 items
    layout.minimumInteritemSpacing = 0

    //set minimum vertical line spacing here between two lines in collectionview
    layout.minimumLineSpacing = 0

    //apply defined layout to collectionview
    collectionView!.collectionViewLayout = layout

}

Điều này được xác minh trên Xcode 8.0 với Swift 3.


8
let layout = myCollectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.minimumLineSpacing = 8

4

Swift 4

let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
collectionViewLayout?.sectionInset = UIEdgeInsetsMake(0, 20, 0, 40) 
collectionViewLayout?.invalidateLayout()

1

Đối với Swift 3 và XCode 8, điều này đã hoạt động. Thực hiện theo các bước dưới đây để đạt được điều này: -

viewDidLoad()
    {
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        var width = UIScreen.main.bounds.width
        layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
    width = width - 10
    layout.itemSize = CGSize(width: width / 2, height: width / 2)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        collectionView!.collectionViewLayout = layout
    }

3
Làm thế nào để tính đến thực tế nếu bạn có nhiều phần
Nikhil Pandey

nó chỉ dành cho 1 cột (phần)
user924

0

Đối với Swift 3+ và Xcode 9+ Hãy thử sử dụng cái này

extension ViewController: UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    let collectionWidth = collectionView.bounds.width
    return CGSize(width: collectionWidth/3, height: collectionWidth/3)

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return 0

}

0

Swift 5: Đối với các không gian phân bố đồng đều giữa các ô có chiều rộng ô động để tận dụng tối đa không gian vùng chứa, bạn có thể sử dụng đoạn mã bên dưới bằng cách cung cấp giá trị tối thiểu .

private func collectionViewLayout() -> UICollectionViewLayout {
    
    let layout = UICollectionViewFlowLayout()
    layout.sectionHeadersPinToVisibleBounds = true
    // Important: if direction is horizontal use minimumItemSpacing instead. 
    layout.scrollDirection = .vertical
    
    let itemHeight: CGFloat = 240
    let minCellWidth :CGFloat = 130.0
    let minItemSpacing: CGFloat = 10
    let containerWidth: CGFloat = self.view.bounds.width
    let maxCellCountPerRow: CGFloat =  floor((containerWidth - minItemSpacing) / (minCellWidth+minItemSpacing ))
    
    let itemWidth: CGFloat = floor( ((containerWidth - (2 * minItemSpacing) - (maxCellCountPerRow-1) * minItemSpacing) / maxCellCountPerRow  ) )
    // Calculate the remaining space after substracting calculating cellWidth (Divide by 2 because of left and right insets)
    let inset = max(minItemSpacing, floor( (containerWidth - (maxCellCountPerRow*itemWidth) - (maxCellCountPerRow-1)*minItemSpacing) / 2 ) )

    
    layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
    layout.minimumInteritemSpacing = min(minItemSpacing,inset)
    layout.minimumLineSpacing = minItemSpacing
    layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)

    
    return layout
}
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.