Як програмно встановити ширину та висоту UICollectionViewCell


103

Я намагаюся реалізувати a CollectionView. Коли я використовую авторозкладку, мої комірки не змінюватимуть розмір, а їх вирівнювання.

Тепер я хотів би змінити їх розміри на наприклад

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

Я спробував встановити у своєму CellForItemAtIndexPath

collectionCell.size = size

це не спрацювало, хоча.

Чи є спосіб досягти цього?

редагувати :

Здається, відповіді змінять лише ширину та висоту мого CollectionView. Чи можливі конфлікти в обмеженнях? Будь-які ідеї щодо цього?

Відповіді:


267

За допомогою цього методу можна встановити спеціальну ширину висоти комірки.

Обов’язково додайте ці протоколи

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

Якщо ви використовуєте swift 5 або xcode 11 і пізніших версій, вам потрібно налаштуватися Estimate Sizeна noneвикористання раскадровки, щоб вона працювала належним чином. Якщо ви не встановите, що нижче, код не буде працювати, як очікувалося.

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

Свіфт 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 - ось що робить фокус
Lance Samaria

5
Встановлення оціночного розміру як жодного не працювало для мене. Дякую @PinkeshGjr
Мохан

5
я радий, що знайшов це, я витратив 2 години, переслідуючи це, лише щоб навчитися магічному "Розрахувати розмір до
нуля

3
встановити для оціночного розміру жодне не зберігало мої дні.
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)
    }
}

Не забудьте використовувати макет потоку, а не нестандартний. Тоді твій єдиний працював на мене. Дякую!
Шон,

як ми можемо дати тут динамічну висоту, даючи статичну висоту як 100,0
сангаві

65

Якщо хтось використовує розкадровку і замінює UICollectionViewDelegateFlowLayout, тоді в swift 5 та Xcode 11 також встановіть для оціночного розміру значення None введіть тут опис зображення


2
Це було корисно. Дякую!!
Naval Hasan

Це, безумовно, було те, що я збирався звести з розуму. Якщо ви не встановите для нього значення none, ви не зможете побачити правильний розмір, який ви вказали в методі sizeForItem.
Юсуф Каміль АК

2
Встановлення оціночного розміру для жодного не виправило все
MMK

2
Розмір орієнтовного розміру Thnx не
вирішено

2
Гарне виправлення. Ось мій діагноз цього питання в відповідно до документацією компанії Apple : UICollectionViewFlowLayoutздається, по замовчуванням , estimatedItemSizeщоб UICollectionViewFlowLayout.automaticSizeпри використанні IB , хоча документація говорить вона повинна по замовчуванням CGSizeZero. Як заявляє Apple, automaticSize"дозволяє саморозмір клітинок для перегляду колекції". Ось чому інші зміни розміру в IB нічого не роблять.
Ендрю Кірна,

20

Нарешті отримав відповідь. Вам слід продовжити. UICollectionViewDelegateFlowLayout
Це повинно працювати з відповідями вище.


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

Насправді я зробив розширення як з джерелами даних, так і з протоколами delegateFlowLayout, і воно не спрацювало. Що спрацювало, було відокремлення частини FlowLayout до власного розширення. Не знаю, чому, але це швидко спрацювало 3.
Скайуокер,

15

стрімкий 4.1

У вас є два способи змінити розмір 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 😂
Ендрю Кірна

12

Співвідношення розміру відповідно до розміру 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
Ну, все залежить, коли ви це зробите. Ви не показали свій справжній код, тож хто знає, що ви робите? Запевняю, це спрацьовує.
matt

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 колекція подання колекція приклад перегляду 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)
}

///// зразок повного коду

create on view collection і collectionview комірка в раскадровці дають посилання на колекцію як
@IBOutlet слабкий 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

Свіфт 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

2020, абсолютно простий спосіб:

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 в оцінці розміру клітинки Розмір до жодного, а у вашому ViewController вам потрібен був метод делегата для реалізації цього методу: optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize


0

Спробуйте використати метод UICollectionViewDelegateFlowLayout. У Xcode 11 або пізнішої версії вам потрібно встановити для Розрахункового розміру значення "нічого" з розкадрування.

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". "Я" для ініціалізатора.

Не так просто додати ініціалізатор до подання колекції. Ось загальний підхід:

Перегляд колекції ... з ініціалізатором:

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

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