Cara menyetel Lebar dan Tinggi UICollectionViewCell secara terprogram


111

Saya mencoba menerapkan CollectionView. Saat saya menggunakan Autolayout, sel saya tidak akan mengubah ukurannya, tetapi perataannya.

Sekarang saya lebih suka mengubah ukurannya menjadi mis

//var size = CGSize(width: self.view.frame.width/10, height: self.view.frame.width/10)

Saya mencoba mengatur di saya CellForItemAtIndexPath

collectionCell.size = size

itu tidak berhasil.

Apakah ada cara untuk mencapai ini?

edit :

Tampaknya, jawabannya hanya akan mengubah lebar dan tinggi CollectionView saya sendiri. Apakah ada kemungkinan konflik dalam Kendala? Ada ide tentang itu?

Jawaban:


288

Gunakan metode ini untuk menyetel lebar tinggi sel khusus.

Pastikan untuk menambahkan protokol ini

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

Jika Anda menggunakan cepat 5 atau Xcode 11 dan kemudian Anda perlu set Estimate Sizeuntuk nonemenggunakan storyboard untuk membuatnya bekerja dengan baik. Jika Anda tidak mengatur bahwa kode di bawah ini tidak akan bekerja seperti yang diharapkan.

masukkan deskripsi gambar di sini

Swift 4 atau Nanti

extension YourViewController: UICollectionViewDelegate {
    //Write Delegate Code Here
}

extension YourViewController: UICollectionViewDataSource {
    //Write DataSource Code Here
}

extension YourViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: screenWidth, height: screenWidth)
    }
}

Objective-C

@interface YourViewController : UIViewController<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(CGRectGetWidth(collectionView.frame), (CGRectGetHeight(collectionView.frame)));
}

1
@RamyAlZuhouri Mengedit jawaban saya, silakan periksa dan beri tahu saya jika kita masih perlu membuatnya lebih jelas
PinkeshGjr

8
Saya sudah terbiasa melakukan segala sesuatu secara terprogram sehingga ini tampak begitu asing bagi saya sekarang. Dalam pengaturan Storyboard, Estimated Size menjadi None dan menambahkan UICollectionViewDelegateFlowLayout adalah triknya
Lance Samaria

6
Menyetel Perkiraan Ukuran menjadi tidak ada yang berhasil untuk saya. Terima kasih @PinkeshGjr
Mohan

6
Saya senang saya menemukan ini, saya menyia-nyiakan 2 jam mengejar ini hanya untuk mempelajari 'Estimate Size to none' yang
ajaib

3
atur Perkiraan Ukuran menjadi tidak ada yang menyelamatkan hari-hari saya.
tounaobun

73

Pastikan untuk menambahkan protokol UICollectionViewDelegateFlowLayoutdi classdeklarasi Anda

class MyCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout
{
    //MARK: - UICollectionViewDelegateFlowLayout

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
    {
       return CGSize(width: 100.0, height: 100.0)
    }
}

Jangan lupa menggunakan tata letak aliran dan bukan custom. Maka milikmu adalah satu-satunya yang berhasil untukku. Terima kasih!
Sean

bagaimana kita bisa memberikan tinggi dinamis di sini memberikan tinggi statis sebagai 100,0
sangavi

68

Jika seseorang menggunakan storyboard dan menimpa UICollectionViewDelegateFlowLayout maka di swift 5 dan Xcode 11 juga atur Estimate size menjadi None masukkan deskripsi gambar di sini


2
Itu sangat membantu. Terima kasih!!
Naval Hasan

3
Menetapkan ukuran perkiraan menjadi tidak ada yang memperbaiki semuanya
MMK

2
Thnx pengaturan perkiraan ukuran tidak ada yang diperbaiki oleh masalah
Salman500

2
Perbaikan yang bagus. Inilah diagnosis saya tentang masalah ini menurut dokumentasi Apple : UICollectionViewFlowLayouttampaknya defaultestimatedItemSize untuk UICollectionViewFlowLayout.automaticSizesaat menggunakan IB meskipun dokumentasi mengatakan itu harus default ke CGSizeZero. Seperti yang dinyatakan Apple, automaticSize"mengaktifkan sel ukuran sendiri untuk tampilan koleksi Anda." Itu sebabnya perubahan ukuran lain di IB tidak melakukan apa-apa.
Andrew Kirna

1
hanya menyelamatkan saya berjam-jam Saya telah berusaha untuk menemukan perbaikan selamanya
Ray Ray

20

Akhirnya mendapat jawabannya. Anda harus memperpanjang UICollectionViewDelegateFlowLayout
Ini harus bekerja dengan jawaban di atas.


Bisakah Anda menulis contoh?
Mamdouh El Nakeeb

Sebenarnya saya membuat ekstensi dengan protokol sumber data dan delegateFlowLayout dan tidak berhasil. Apa yang berhasil adalah memisahkan bagian FlowLayout menjadi perpanjangannya sendiri. Tidak yakin mengapa tetapi itu berhasil di swift 3.
Skywalker

15

swift 4.1

Anda memiliki 2 cara untuk mengubah ukuran CollectionView.
Cara pertama -> tambahkan protokol ini UICollectionViewDelegateFlowLayout
untuk Dalam kasus saya, saya ingin membagi sel menjadi 3 bagian dalam satu baris. Saya melakukan kode ini di bawah

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource ,UICollectionViewDelegateFlowLayout{
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
    {
            // In this function is the code you must implement to your code project if you want to change size of Collection view
            let width  = (view.frame.width-20)/3
            return CGSize(width: width, height: width)
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return collectionData.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
        if let label = cell.viewWithTag(100) as? UILabel {
            label.text = collectionData[indexPath.row]
        }
        return cell
    }
}

Cara kedua -> Anda tidak perlu menambahkan UICollectionViewDelegateFlowLayout tetapi Anda harus menulis beberapa kode dalam fungsi viewDidload sebagai gantinya seperti kode di bawah ini

class ViewController: UIViewController {
@IBOutlet weak var collectionView1: UICollectionView!
        var collectionData = ["1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12."]

    override func viewDidLoad() {
        super.viewDidLoad()
        let width = (view.frame.width-20)/3
        let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
        layout.itemSize = CGSize(width: width, height: width) 
    }
}


extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {


    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return collectionData.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
        if let label = cell.viewWithTag(100) as? UILabel {
            label.text = collectionData[indexPath.row]
        }

        return cell
    }
}

Apapun yang Anda tulis kode sebagai cara pertama atau kedua Anda akan mendapatkan hasil yang sama seperti di atas. Saya menulisnya. Itu berhasil untuk saya

masukkan deskripsi gambar di sini


2
Langsung dari raywenderlich.com 😂
Andrew Kirna

13

Rasio ukuran menurut ukuran iPhone:

Inilah yang dapat Anda lakukan untuk memiliki lebar dan tinggi yang berbeda untuk sel sehubungan dengan ukuran iPhone:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    let width = (self.view.frame.size.width - 12 * 3) / 3 //some width
    let height = width * 1.5 //ratio
    return CGSize(width: width, height: height)
}

Dan mungkin Anda juga harus menonaktifkan batasan AutoLayout pada sel agar jawaban ini berfungsi.


Saya mencoba ini dan semua solusi di atas tetapi konten dalam sel tidak otomatis, bagaimana saya dapat memperbaikinya
Biasi Wiga

7

Tampilan koleksi memiliki objek tata letak . Dalam kasus Anda, ini mungkin adalah tata letak aliran ( UICollectionViewFlowLayout ). Setel itemSizeproperti tata letak aliran .


Sudah mencoba ini. memberi saya masalah yang sama seperti sebelumnya. entah bagaimana CollectionView saya mengubah ukurannya daripada sel saya.
JVS

2
Nah, itu semua tergantung kapan Anda melakukannya. Anda belum menunjukkan kode asli Anda, jadi siapa yang tahu apa yang Anda lakukan? Saya jamin itu berhasil.
matt

7

di Swift3 dan Swift4 Anda bisa mengubah ukuran sel dengan menambahkan UICollectionViewDelegateFlowLayout dan mengimplementasikannya seperti ini:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 100, height: 100)
    }

atau jika membuat UICollectionView secara terprogram, Anda dapat melakukannya seperti ini:

    let layout = UICollectionViewFlowLayout()
                    layout.scrollDirection = .horizontal //this is for direction
                    layout.minimumInteritemSpacing = 0 // this is for spacing between cells
                    layout.itemSize = CGSize(width: view.frame.width, height: view.frame.height) //this is for cell size
let collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)

4

swift4 swift 4 ios collection view collectionview contoh xcode contoh kode kerja terbaru

Tambahkan ini di bagian Delegasi di atas

UICollectionViewDelegateFlowLayout

dan gunakan fungsi ini

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = (self.view.frame.size.width - 20) / 3 //some width
    let height = width * 1.5 //ratio
    return CGSize(width: width, height: height)
}

///// contoh kode lengkap

buat pada tampilan koleksi dan sel tampilan koleksi di storyboard memberikan referensi ke koleksi sebagai
@IBOutlet weak var cvContent: UICollectionView!

tempel ini di View controller

 import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    var arrVeg = [String]()
    var arrFruits = [String]()
    var arrCurrent = [String]()
    
    @IBOutlet weak var cvContent: UICollectionView!
    
  
    
    override func viewDidLoad() {
        super.viewDidLoad()
        arrVeg = ["Carrot","Potato", "Tomato","Carrot","Potato", "Tomato","Carrot","Potato", "Tomato","Carrot","Potato", "Tomato"]
        
        arrVeg = ["Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange","Mango","Papaya","Orange"]
        
        
        arrCurrent = arrVeg
    }
    //MARK: - CollectionView
    


    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = (self.view.frame.size.width - 20) / 3 //some width
        let height = width * 1.5 //ratio
        return CGSize(width: width, height: height)
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {

        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        
        return arrCurrent.count
    }
    
    
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ContentCollectionViewCell
        cell.backgroundColor =  UIColor.green
        return cell
    }
}

2

Coba metode di bawah ini

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSize(width: 100.0, height: 100.0)
}

2

Swift 5 Secara terprogram

lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal

        //Provide Width and Height According to your need
        let cellWidth = UIScreen.main.bounds.width / 10
        let cellHeight = UIScreen.main.bounds.height / 10
        layout.itemSize = CGSize(width: cellWidth, height: cellHeight)

        //You can also provide estimated Height and Width
        layout.estimatedItemSize = CGSize(width: cellWidth, height: cellHeight)

        //For Setting the Spacing between cells
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0

        return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    }()

1
**Swift 5**
To make this work you have to do the following.

Add these protocols

 - UICollectionViewDelegate


 - UICollectionViewDataSource


 - UICollectionViewDelegateFlowLayout

Your code will then look like this

extension YourViewController: UICollectionViewDelegate {
    //Write Delegate Code Here
}

extension YourViewController: UICollectionViewDataSource {
    //Write DataSource Code Here
}

extension YourViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: screenWidth, height: screenWidth)
    }
}

Now the final and crucial step to see this take effect is to go to your viedDidLoad function inside your Viewcontroller.

    override func viewDidLoad() {
        super.viewDidLoad()
        collection.dataSource = self // Add this
        collection.delegate = self // Add this

        // Do any additional setup after loading the view.
    }

Without telling your view which class the delegate is it won't work.

1

#Cara yang benar-benar sederhana:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource {

#Anda harus menambahkan "UICollectionViewDelegateFlowLayout" atau, tidak ada pelengkapan otomatis:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

#Type "sizeForItemAt ...". Kamu sudah selesai!

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {
 
     func collectionView(_ collectionView: UICollectionView,
      layout collectionViewLayout: UICollectionViewLayout,
      sizeForItemAt indexPath: IndexPath) -> CGSize {
     
     return CGSize(width: 37, height: 63)
}

Itu dia.

Contoh, jika Anda ingin "setiap sel mengisi seluruh tampilan koleksi":

     guard let b = view.superview?.bounds else { .. }
     return CGSize(width: b.width, height: b.height)

0

Cara lain adalah dengan menyetel nilai secara langsung di tata letak aliran

    let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
    layout.itemSize = CGSize(width: size, height: size)

0

Jadi, Anda perlu menyetel dari storyboard untuk atribut untuk collectionView di bagian sel, memperkirakan Ukuran ke tidak ada, dan di ViewController Anda perlu memiliki metode delegasi untuk mengimplementasikan metode ini: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize


0

Coba gunakan metode UICollectionViewDelegateFlowLayout. Di Xcode 11 atau lebih baru, Anda perlu mengatur Perkiraan Ukuran ke tidak ada dari storyboard.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: 
UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let padding: CGFloat =  170
    let collectionViewSize = advertCollectionView.frame.size.width - padding
    return CGSize(width: collectionViewSize/2, height: collectionViewSize/2)
}

0

Cara sederhana:

Jika Anda hanya membutuhkan ukuran tetap sederhana :

class SizedCollectionView: UIICollectionView {
    override func common() {
        super.common()
        let l = UICollectionViewFlowLayout()
        l.itemSize = CGSize(width: 42, height: 42)
        collectionViewLayout = l
    }
}

Itu saja yang ada untuk itu.

Di storyboard, ubah saja kelas dari UICollectionView ke SizedCollectionView.

Tapi !!!

Perhatikan kelas dasar ada "UI 'I' CollectionView". 'I' untuk Penginisialisasi.

Tidak mudah menambahkan penginisialisasi ke tampilan koleksi. Berikut pendekatan yang umum:

Tampilan koleksi ... dengan penginisialisasi:

import UIKit

class UIICollectionView: UICollectionView {
    private var commoned: Bool = false
    
    override func didMoveToWindow() {
        super.didMoveToWindow()
        if window != nil && !commoned {
            commoned = true
            common()
        }
    }
    
    internal func common() {
    }
}

Di sebagian besar proyek, Anda memerlukan "tampilan koleksi dengan penginisialisasi". Jadi Anda mungkin tetap akan memiliki UIICollectionView(perhatikan I ekstra untuk Penginisialisasi!) Dalam proyek Anda.


0

Swift 5, pengaturan Programmatic UICollectionView Lebar dan tinggi sel

// MARK: MyViewController

final class MyViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
        let layout = UICollectionViewFlowLayout()
        let spacing: CGFloat = 1
        let numOfColumns: CGFloat = 3
        let itemSize: CGFloat = (UIScreen.main.bounds.width - (numOfColumns - spacing) - 2) / 3
        layout.itemSize = CGSize(width: itemSize, height: itemSize)
        layout.minimumInteritemSpacing = spacing
        layout.minimumLineSpacing = spacing
        layout.sectionInset = UIEdgeInsets(top: spacing, left: spacing, bottom: spacing, right: spacing)
        return layout
    }()
    
    private lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: collectionViewLayout)
        collectionView.backgroundColor = .white
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        return collectionView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureCollectionView()
    }
    
    private func configureCollectionView() {
        view.addSubview(collectionView)
        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
        ])
        collectionView.register(PhotoCell.self, forCellWithReuseIdentifier: "PhotoCell")
    }
    
    // MARK: UICollectionViewDataSource

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 20
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
        cell.backgroundColor = .red
        return cell
    }
    
}

// MARK: PhotoCell

final class PhotoCell: UICollectionViewCell {
    
    lazy var imageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.layer.masksToBounds = true
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init?(coder:) not implemented")
    }
    
    func setupViews() {
        addSubview(imageView)
        NSLayoutConstraint.activate([
            topAnchor.constraint(equalTo: topAnchor),
            bottomAnchor.constraint(equalTo: bottomAnchor),
            leadingAnchor.constraint(equalTo: leadingAnchor),
            trailingAnchor.constraint(equalTo: trailingAnchor)
        ])
    }
    
}

0

Jika, seperti saya, Anda perlu menjaga tata letak aliran kustom Anda yang itemSizedinamis diperbarui berdasarkan lebar koleksi pandangan Anda, Anda harus menimpa Anda UICollectionViewFlowLayout's prepare()metode. Berikut adalah video WWDC yang mendemonstrasikan teknik ini .

class MyLayout: UICollectionViewFlowLayout {
    
    override func prepare() {
        super.prepare()
        
        guard let collectionView = collectionView else { return }
        
        itemSize = CGSize(width: ..., height: ...)
    }
    
}

-4

Ini adalah versi saya, temukan rasio yang sesuai untuk mendapatkan ukuran sel sesuai kebutuhan Anda.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
return CGSizeMake(CGRectGetWidth(collectionView.frame)/4, CGRectGetHeight(collectionView.frame)/4); 
} 
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.