UICollectionViewCell Genişliği ve Yüksekliğini programlı olarak ayarlama


114

Bir uygulamaya çalışıyorum CollectionView. Otomatik Düzen'i kullandığımda hücrelerim boyutu değiştirmeyecek, ancak hizalamalarını değiştirecek.

Şimdi boyutlarını ör.

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

Ayarlamayı denedim CellForItemAtIndexPath

collectionCell.size = size

yine de işe yaramadı.

bunu arşivlemenin bir yolu var mı?

düzenle :

Görünüşe göre, cevaplar sadece CollectionView genişliğimi ve yüksekliğimi değiştirecek. Kısıtlamalarda olası çatışma var mı? Bununla ilgili bir fikrin var mı?

Yanıtlar:


303

Özel hücre yüksekliği genişliğini ayarlamak için bu yöntemi kullanın.

Bu protokolleri eklediğinizden emin olun

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

Eğer kullanıyorsanız swift 5 veya xcode 11 ve üstü sete gerek Estimate Sizeiçin nonedüzgün çalışmasını sağlamak amacıyla film şeridi kullanarak. Bunu aşağıdaki kadar ayarlamazsanız, kod beklendiği gibi çalışmayacaktır.

görüntü açıklamasını buraya girin

Swift 4 veya Daha Sonra

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

Amaç-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 Cevabımı düzenledim, lütfen kontrol edin ve daha net hale
getirmemiz gerekip

8
Her şeyi programlı bir şekilde yapmaya o kadar alışkınım ki bu artık bana çok yabancı geliyor. Storyboard belirlerken Tahmini Boyut için Hiçbiri ve ekleme UICollectionViewDelegateFlowLayout trick yaptığı iştir
Lance Samiriye

6
Tahmini Boyutu hiçbiri olarak ayarlamak benim için işe yaramadı. Teşekkür ederim @PinkeshGjr
Mohan

6
Bunu bulduğuma sevindim, bunun peşinden 2 saatimi sadece büyülü 'Tahmini Boyut
Yok'u

4
Tahmini Boyut'u hiçbiri günlerimi kurtarmadı olarak ayarla.
tounaobun

73

Protokolünü eklemek için emin olun UICollectionViewDelegateFlowLayoutsizin de classbildiriminde

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

Özel değil akış düzenini kullanmayı unutmayın. O zaman benim için çalışan tek kişi seninki. Teşekkürler!
Sean

100.0 statik yükseklik vererek burada dinamik yüksekliği nasıl verebiliriz
sangavi

71

Biri storyboard kullanıyorsa ve UICollectionViewDelegateFlowLayout'u geçersiz kılıyorsa, o zaman swift 5 ve Xcode 11'de de Estimate size öğesini None olarak ayarlayın görüntü açıklamasını buraya girin


2
Bu yardımcı oldu. Teşekkürler!!
Naval Hasan

4
Tahmin boyutunu hiçbiri olarak ayarlamak her şeyi
düzeltmedi

2
Thnx

2
İyi düzeltme. İşte Apple'ın belgelerine göre bu sorunun teşhisi : BelgelerUICollectionViewFlowLayout varsayılan estimatedItemSizeolarak UICollectionViewFlowLayout.automaticSizeayarlanması gerektiğini söylese de IB'yi kullanırken varsayılan olarak görünüyor CGSizeZero. Apple'ın belirttiği gibi, automaticSize"koleksiyon görünümünüz için kendi boyutlarını belirleyen hücreleri etkinleştirir." Bu yüzden IB'deki diğer boyut değişiklikleri hiçbir şey yapmaz.
Andrew Kirna

1
Sonsuza kadar bir çözüm bulmaya çalıştığım saatlerden tasarruf ettim
Ray Ray

20

Sonunda cevabı aldım. Sen uzanmalıdır UICollectionViewDelegateFlowLayout
Bu, yukarıda cevapları ile çalışıyor olması gerekir.


Bir örnek yazabilir misin?
Memduh El Nakeeb

Aslında hem datasource hem de delegateFlowLayout protokolleriyle bir uzantı yaptım ve çalışmadı. İşe yarayan şey, FlowLayout bölümünü kendi uzantısına ayırmaktı. Neden emin değilim ama hızlı 3'te işe yaradı.
Skywalker

15

hızlı 4.1

CollectionView boyutunu değiştirmek için 2 yolunuz var.
İlk yol -> bu protokolü ekleyin UICollectionViewDelegateFlowLayout
Benim durumumda hücreyi bir satırda 3 parçaya bölmek istiyorum. Bu kodu aşağıda yaptım

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

İkinci yol -> sen yok eklemek zorunda UICollectionViewDelegateFlowLayout ancak bazı kod yazmak zorunda viewDidLoad fonksiyonu aşağıda kodu olarak yerine

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

Birinci yol veya ikinci yol olarak bir kod yazarsanız, yukarıdakiyle aynı sonucu alırsınız. Ben yazdım. Benim için çalıştı

görüntü açıklamasını buraya girin


2
Doğrudan raywenderlich.com'dan 😂
Andrew Kirna

13

İPhone boyutuna göre boyut oranı:

İPhone boyutuyla ilgili olarak hücrelerin farklı genişliğine ve yüksekliğine sahip olmak için yapabilecekleriniz:

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

Ve belki de bu cevabın çalışması için hücredeki Otomatik Yerleşim kısıtlamalarını devre dışı bırakmalısınız.


Bunu ve yukarıdaki tüm çözümleri denedim ancak bir hücredeki içerik otomatik olarak yeniden boyutlandırılmıyor, bunu nasıl düzeltebilirim
Biasi Wiga

7

Koleksiyon görünümünün bir düzen nesnesi vardır. Sizin durumunuzda, muhtemelen bir akış düzenidir ( UICollectionViewFlowLayout ). Akış düzeninin itemSizeözelliğini ayarlayın .


Bunu denedim. bana eskisi gibi aynı sorunu veriyor. Bir şekilde CollectionView'um hücrelerim yerine boyutunu değiştiriyor.
JVS

2
Her şey ne zaman yapacağına bağlı . Gerçek kodunuzu göstermediniz, peki ne yaptığınızı kim bilebilir? Sizi temin ederim işe yarıyor.
mat

7

içinde swift3 ve Swift4 size ekleyerek hücre boyutunu değiştirebilirsiniz UICollectionViewDelegateFlowLayout ve bu gibi uygulanması:

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

veya programlı olarak UICollectionView oluşturursanız, bunu şu şekilde yapabilirsiniz:

    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 koleksiyon görünümü koleksiyonu görüntüleme örneği xcode en son kod çalışma örneği

Bunu üstteki Temsilci bölümüne ekleyin

UICollectionViewDelegateFlowLayout

ve bu işlevi kullanın

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

///// örnek tam kod

storyboard'daki koleksiyon görünümünde oluştur ve koleksiyon görünümü hücresi, koleksiyona
@IBOutlet zayıf var cvContent: UICollectionView olarak referans verir!

bunu Görünüm denetleyicisine yapıştır

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

3

Swift 5 Programlı Olarak

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

2

Aşağıdaki yöntemi deneyin

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

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

# Kesinlikle basit yol:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource {

# "UICollectionViewDelegateFlowLayout" eklemelisiniz veya otomatik tamamlama yok:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

# "SizeForItemAt ..." yazın. Sen bittin!

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

Bu kadar.

Örneğin, "her hücre tüm koleksiyon görünümünü doldurur" istiyorsanız:

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

0

Diğer bir yol, değeri doğrudan akış düzeninde ayarlamaktır

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

0

Bu nedenle, hücre bölümünde collectionView özniteliği için film şeridinden boyut tahminini yok olarak ayarlamanız gerekir ve ViewController'ınızda bu yöntemi uygulamak için temsilci yöntemine ihtiyacınız vardır: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize


0

UICollectionViewDelegateFlowLayout yöntemini kullanmayı deneyin. Xcode 11 veya sonraki sürümlerde, Tahmin Etme boyutunu film şeridinden sıfır olarak ayarlamanız gerekir.

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

Basit bir yol:

Sadece basit bir sabit boyuta ihtiyacınız varsa :

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

Hepsi bu kadar.

Film şeridinde, sınıfı UICollectionView'den SizedCollectionView'a değiştirin.

Fakat !!!

Temel sınıfın "UI 'I' CollectionView" olduğuna dikkat edin. Başlatıcı için 'I'.

Koleksiyon görünümüne başlatıcı eklemek o kadar kolay değil. İşte yaygın bir yaklaşım:

Koleksiyon görünümü ... başlatıcı ile:

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

Çoğu projede, "başlatıcılı bir koleksiyon görünümüne" ihtiyacınız vardır. Yani muhtemelen UIICollectionViewprojenizde (Initializer için fazladan I notuna dikkat edin!)


0

Swift 5, Programmatic UICollectionView ayarı Hücre genişliği ve yüksekliği

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

Benim gibi sen var özel akış düzenini tutmak gerekiyorsa itemSizedinamik toplama görünümün genişliğine göre güncelleme, size geçersiz kılar UICollectionViewFlowLayout'ın prepare()metodunu. İşte bu tekniği gösteren bir WWDC videosu .

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

-4

Bu benim versiyonum, ihtiyacınıza göre hücre boyutunu elde etmek için uygun oranınızı bulun.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
return CGSizeMake(CGRectGetWidth(collectionView.frame)/4, CGRectGetHeight(collectionView.frame)/4); 
} 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.