Как программно установить ширину и высоту UICollectionViewCell


111

Я пытаюсь реализовать CollectionView. Когда я использую Autolayout, мои ячейки меняют не размер, а их выравнивание.

Теперь я бы предпочел изменить их размеры, например, на

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

Я попробовал установить в своем CellForItemAtIndexPath

collectionCell.size = size

но это не сработало.

Есть ли способ добиться этого?

редактировать :

Кажется, что ответы изменят только ширину и высоту моего CollectionView. Возможен ли конфликт в ограничениях? Есть идеи по этому поводу?

Ответы:


288

Используйте этот метод, чтобы установить пользовательскую ширину высоты ячейки.

Обязательно добавьте эти протоколы

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

Если вы используете быстрые 5 или Xcode 11 , а затем вам нужно установить Estimate Sizeдля noneиспользования раскадровки для того , чтобы заставить его работать правильно. Если вы не установите это значение, приведенный ниже код не будет работать должным образом.

введите описание изображения здесь

Swift 4 или новее

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

Цель-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 Отредактировал мой ответ, пожалуйста, проверьте и дайте мне знать, если нам все еще нужно сделать его более ясным
PinkeshGjr

8
Я настолько привык делать все программно, что сейчас это кажется мне таким чуждым. В раскадровке установка « Расчетный размер» на « Нет» и добавление UICollectionViewDelegateFlowLayout - вот что дает трюк
Лэнс Самария,

6
У меня не сработало установка для оценочного размера значения none. Спасибо @PinkeshGjr
Мохан

6
Я рад, что нашел это, я потратил 2 часа на погоню за этим, только чтобы узнать волшебное «Не
оценивать

3
Установите для Estimate Size значение none, что спасло мои дни.
tounaobun

73

Обязательно добавьте протокол UICollectionViewDelegateFlowLayoutв classдекларацию

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

Не забывайте использовать макет потока, а не пользовательский. Тогда у меня сработало только твое. Благодарность!
Шон

как мы можем
указать

68

Если вы используете раскадровку и переопределяете UICollectionViewDelegateFlowLayout, тогда в Swift 5 и Xcode 11 также установите для размера оценки значение None введите описание изображения здесь


2
Это было полезно. Благодарность!!
Naval Hasan

3
Установка сметного размера равным "Нет" все
решила

2
Thnx устанавливает для размера оценки значение "
Отсутствие

2
Хорошее исправление. Вот мой диагноз этого вопроса в соответствии с документацией компании Apple : UICollectionViewFlowLayoutкажется, по умолчанию , estimatedItemSizeчтобы UICollectionViewFlowLayout.automaticSizeпри использовании IB , хотя документация говорит она должна по умолчанию CGSizeZero. Как заявляет Apple, automaticSize«позволяет изменять размер ячеек для представления вашей коллекции». Вот почему другие изменения размера в IB ничего не делают.
Эндрю Кирна

1
просто сэкономил мне часы, я вечно пытался найти решение
Рэй Рэй

20

Наконец-то получил ответ. Вы должны расширить UICollectionViewDelegateFlowLayout
Это должно работать с ответами выше.


Не могли бы вы написать пример?
Mamdouh El Nakeeb

На самом деле я сделал расширение с протоколами источника данных и делегатаFlowLayout, и это не сработало. Что сработало, так это разделение части FlowLayout на собственное расширение. Не уверен, почему, но это сработало в Swift 3.
Скайуокер

15

быстрый 4.1

У вас есть 2 способа изменить размер CollectionView.
Первый способ -> добавить этот протокол UICollectionViewDelegateFlowLayout
для В моем случае я хочу разделить ячейку на 3 части в одной строке. Я сделал этот код ниже

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

Второй способ -> вам не нужно добавлять UICollectionViewDelegateFlowLayout, но вместо этого вам нужно написать код в функции viewDidload как код ниже

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

Независимо от того, что вы пишете код первым или вторым способом, вы получите тот же результат, что и выше. Я это написал. Это сработало для меня

введите описание изображения здесь


2
Прямо с сайта raywenderlich.com 😂
Эндрю Кирна

13

Соотношение размеров в зависимости от размера iPhone:

Вот что вы можете сделать, чтобы иметь разную ширину и высоту для ячеек в зависимости от размера 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)
}

И, возможно, вам также следует отключить ограничения AutoLayout для ячейки, чтобы этот ответ работал.


Я пробовал это и все вышеперечисленные решения, но содержимое ячейки не меняет размер автоматически, как я могу это исправить
Biasi Wiga

7

В представлении коллекции есть объект макета . В вашем случае это, вероятно, макет потока ( UICollectionViewFlowLayout ). Задайте itemSizeсвойство макета потока .


Пробовал это. дает мне ту же проблему, что и раньше. каким-то образом мой CollectionView меняет его размер, а не мои ячейки.
JVS

2
Ну, все зависит от того, когда вы это сделаете. Вы не показали свой настоящий код, так что кто знает, что вы делаете? Уверяю вас, это работает.
Мэтт

7

в Swift3 и Swift4 вы можете изменить размер ячейки, добавив UICollectionViewDelegateFlowLayout и реализовав его следующим образом:

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

или если программно создать UICollectionView, вы можете сделать это так:

    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 пример последний рабочий образец кода xcode

Добавьте это в раздел "Делегат" вверху

UICollectionViewDelegateFlowLayout

и используйте эту функцию

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

///// пример полного кода

создать в представлении коллекции и ячейке представления коллекции в раскадровке дать ссылку на коллекцию как
@IBOutlet weak var cvContent: UICollectionView!

вставьте это в контроллер просмотра

 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

Попробуйте метод ниже

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

2

Swift 5 программно

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

# Абсолютно простой способ:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource {

# Вы должны добавить "UICollectionViewDelegateFlowLayout", иначе автозаполнение отсутствует:

class YourCollection: UIViewController,
     UICollectionViewDelegate,
     UICollectionViewDataSource,
     UICollectionViewDelegateFlowLayout {

# Введите "sizeForItemAt ...". Готово!

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

Вот и все.

Например, если вы хотите, чтобы «каждая ячейка заполняла всю коллекцию»:

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

0

Другой способ - установить значение непосредственно в макете потока.

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

0

Таким образом, вам нужно установить из раскадровки для атрибута для collectionView в разделе оценки размера ячейки значение none, а в вашем ViewController вам нужен метод делегата для реализации этого метода: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize


0

Попробуйте использовать метод UICollectionViewDelegateFlowLayout. В Xcode 11 или более поздних версиях вам необходимо установить для параметра Estimate Size значение none из раскадровки.

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

Простой способ:

Если вам нужен простой фиксированный размер :

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

Это все, что нужно сделать.

В раскадровке просто измените класс с UICollectionView на SizedCollectionView.

Но !!!

Обратите внимание на базовый класс «UI 'I' CollectionView». «I» для инициализатора.

Не так-то просто добавить инициализатор в представление коллекции. Вот общий подход:

Просмотр коллекции ... с инициализатором:

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

В большинстве проектов вам понадобится «представление коллекции с инициализатором». Так что вы, вероятно, все равно будете иметь UIICollectionView(обратите внимание на дополнительный I для Initializer!) В вашем проекте.


0

Swift 5, программная настройка UICollectionView Ширина и высота ячейки

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

Если, как я, вы должны держать свой пользовательский шаблон Флоу itemSizeдинамически обновляется на основе ширины вашего представления коллекции, вы должны переопределить UICollectionViewFlowLayout«s prepare()метод. Вот видео WWDC, демонстрирующее эту технику .

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

-4

Это моя версия, найдите подходящее соотношение, чтобы получить размер ячейки в соответствии с вашими требованиями.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
return CGSizeMake(CGRectGetWidth(collectionView.frame)/4, CGRectGetHeight(collectionView.frame)/4); 
} 
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.