Bagaimana cara mengatur jarak sel dan rasio ukuran UICollectionView - UICollectionViewFlowLayout?

140

Saya mencoba menambahkan UICollectionViewke ViewController, dan saya perlu memiliki 3 sel 'per baris' tanpa spasi kosong antar sel (seharusnya terlihat seperti kisi). Lebar sel harus sepertiga dari ukuran layar, jadi saya pikir layout.itemlebarnya harus sama. Tapi kemudian saya mendapatkan ini:

layout.itemSize width = screenSize.width / 3

Jika saya mengurangi ukuran itu ( misalnya 7 atau 8 piksel ), itu lebih baik, tetapi sel ketiga di baris tidak sepenuhnya terlihat, dan saya masih memiliki ruang kosong (atas & bawah, dan kiri & kanan).

masukkan deskripsi gambar di sini

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
    }
}
Marko
sumber
Inilah solusinya. Terima kasih.
janu kansagra
Berikut adalah Kode Kerja untuk Swift 4 stackoverflow.com/a/54703798/10150796
Nikunj Kumbhani

Jawaban:

311

Tambahkan 2 baris ini

layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0

Jadi kamu punya:

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

Itu akan menghapus semua ruang dan memberi Anda tata letak kisi:

masukkan deskripsi gambar di sini

Jika Anda ingin kolom pertama memiliki lebar yang sama dengan lebar layar maka tambahkan fungsi berikut:

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

}

Tata letak kisi sekarang akan terlihat seperti (saya juga menambahkan latar belakang biru ke sel pertama): masukkan deskripsi gambar di sini

Peter Todd
sumber
Terima kasih banyak, saya mengharapkan sesuatu yang jauh lebih rumit, dan saya menghabiskan banyak waktu untuk itu. Terima kasih sekali lagi.
Marko
Dan satu hal lagi, apakah ada kemungkinan untuk mengubah layout.itemSize hanya untuk sel pertama? (Saya tahu bahwa saya perlu mengubah cell.frame.size ketika indexPath.row adalah 0, tetapi tidak tahu bagaimana mengubah ukuran tata letak hanya untuk satu item) Lebar elemen pertama harus sama dengan screenWidth .
Marko
1
Hai, Saya memiliki masalah yang sama tetapi saya ingin tahu judul fungsi yang serupa di Tujuan C.
Nada Gamal
1
Oke, Sekarang berfungsi dengan baik, Terima kasih banyak :) Fungsi Objective C: - (CGSize) collectionView: (UICollectionView ) collectionView layout: (UICollectionViewLayout ) collectionViewLayout sizeForItemAtIndexPath: (NSIndexPath *) indexPath {return CGSizeMake (screenWidth / 3, screenWidth / 3 ); }
Nada Gamal
4
terima kasih atas jawaban yang bagus @greentor. mengirim hadiah. Jangan lupa collectionView! .CollectionViewLayout = layout , pembaca
Fattie
50

Untuk Swift 3 dan XCode 8 , ini berhasil. Ikuti langkah-langkah di bawah ini untuk mencapai ini: -

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

Tempatkan kode ini ke dalam fungsi viewDidLoad ().

Nirmit Dagly
sumber
34

Dalam situasi tertentu, Pengaturan UICollectionViewFlowLayoutdalam viewDidLoadatauViewWillAppear mungkin tidak berpengaruh pada collectionView.

Mengatur UICollectionViewFlowLayoutmasukviewDidAppear dapat menyebabkan perubahan ukuran sel dalam runtime.

Solusi Lain, di 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
    }
}
Maor
sumber
Jawaban Hebat! Ini pasti cara Apple untuk melakukannya. Sekarang, Anda tidak tahu cara menyegarkan ketika perangkat mengubah orientasi, bukan?
jlstr
solusi terbaik untuk saya terima kasih
islam XDeveloper
19

Jika Anda mencari Swift 3, Ikuti langkah-langkah untuk mencapainya:

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

}

Ini diverifikasi pada Xcode 8.0 dengan Swift 3.

Dharmendra Kachhadiya
sumber
9
let layout = myCollectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.minimumLineSpacing = 8
jamal zare
sumber
4

Cepat 4

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

Untuk Swift 3 dan XCode 8, ini berhasil. Ikuti langkah-langkah di bawah ini untuk mencapai ini: -

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
    }
Moin Shirazi
sumber
3
Cara memperhitungkan fakta jika Anda memiliki banyak bagian
Nikhil Pandey
ini hanya untuk 1 kolom (bagian)
user924
0

Untuk Swift 3+ dan Xcode 9+ Coba gunakan ini

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

}
Aditya
sumber
0

Swift 5: Untuk ruang yang didistribusikan secara merata antara sel dengan lebar sel dinamis untuk memanfaatkan ruang penampung sebaik-baiknya, Anda dapat menggunakan cuplikan kode di bawah ini dengan memberikan nilai minimumCellWidth .

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
}
deniz yalcin
sumber