Высота UICollectionViewCell по размеру содержимого

ios

#1

Друзья, сижу бьюсь, как сделать высоту UICollectionViewCell по размеру содержимого. В ячейке есть многострочный UILabel. Если текста много - ячейка не растягивается по высоте.


#2

Мне кажется вы не правильно понимаете как это работает.
Растягиваете вой CollectionView как вам нужно, в ячейку вставляете ScrollView, растягиваете его на всю ячейку, дальше уже свой контент вставляете в ScrollView. В таком случае контент больше ячейки, будет в нем скролиться.
Если же у вас вертикальная прокрутка, тогда уже лучше использовать TableView.


#3

А можно ли в TableView сделать так, чтобы было расстояние между ячейками, а не вплотную? Да, мне нужна вертикальная прокрутка, но ячейки должны быть отделены друг от друга.


#4

Как один из вариантов, выставить внутренний padding у ячеек.
Не совсем уверен, но может быть можно как-то сделать это с помощью разделителя, указав ему большую толщину и сделать прозрачным.


#5

Вы нашли решение своей проблемы?


#6

Я все же использовал UICollectionView. Чуть позже выложу решение, когда будет доступ к ноуту.


#7

Я тоже использую коллекшн Вью и застрял на этом моменте


#8

Если тебе просто нужно изменить размер ячейки под размер текста, можно использовать метод

boundingRect(with:options:attributes:) класса NSString

Он возвращает CGRect, узнаешь высоту текста если у тебя ширина задана константно и соотвественно переопределись метод

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize


#9

Нужно сделать вот так


#10

Попробуй сделать кастовую ячейку и там укажи constrains для imageview и для label, у тебя картинка везде скорее всего будет одинакова, ширина label тоже ограничена шириной картинки, а высоту посчитаешь boundingRect(with:options:attributes:) вот так я бы начал делать.
А ячейка просто будет включать два объекта


#11

Спасибо))) завтра попробую


#12

Я использовал свой класс для ячейки CollectionViewCell. В нем прописал такой метод

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    setNeedsLayout()
    layoutIfNeeded()
    
    let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
    
    var frame = layoutAttributes.frame
    frame.size.height = ceil(size.height)
    layoutAttributes.frame = frame
    
    return layoutAttributes
}

#13

Примерно так я себе это представляю

 import UIKit

        @UIApplicationMain
        class AppDelegate: UIResponder, UIApplicationDelegate {

            var window: UIWindow?


            func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
                // Override point for customization after application launch.
                window = UIWindow(frame: UIScreen.main.bounds)
                window?.makeKeyAndVisible()
                let cntr = CollectionVC(collectionViewLayout: UICollectionViewFlowLayout())
                window?.rootViewController = cntr
                return true
            }
        }


        import UIKit

        class CollectionVC: UICollectionViewController {
            
            let words = ["Hello my friesnd", "is", "Just shut up text text text", "test"]
            
            override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
                collectionView?.collectionViewLayout.invalidateLayout()
            }

            override func viewDidLoad() {
                super.viewDidLoad()
                
                self.collectionView?.backgroundColor = UIColor.white
                self.collectionView?.register(CustomCollectionVC.self, forCellWithReuseIdentifier: "cell")
                self.collectionView?.contentInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
            }
        }

        extension CollectionVC: UICollectionViewDelegateFlowLayout {
            override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                return 4
            }
            
            func estimateFrameForLabel(label: String) -> CGRect {
                let size = CGSize(width: 60, height: 600)
                let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
                let attributes = [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 16)]
                let frame = NSString(string: label).boundingRect(with: size, options: options, attributes: attributes, context: nil)
                return frame
            }
            
            func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
                let string = words[indexPath.row]
                let height = 60 + estimateFrameForLabel(label: string).height + 10
                return CGSize(width: 60, height: height)
            }
            
            override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                let cell = self.collectionView?.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCollectionVC
                
                let string = words[indexPath.row]
                let height = estimateFrameForLabel(label: string).height
                
                cell.imageView.backgroundColor = UIColor.blue
                cell.label.text = string
                cell.label.backgroundColor = UIColor.lightGray
                cell.height?.constant = height + 10
                
                return cell
            }
        }

        import UIKit

        class CustomCollectionVC: UICollectionViewCell {
            
            let imageView: UIImageView = {
                let img = UIImageView()
                img.translatesAutoresizingMaskIntoConstraints = false
                return img
            }()
            
            let label: UILabel = {
                let lbl = UILabel()
                lbl.translatesAutoresizingMaskIntoConstraints = false
                lbl.font = UIFont.systemFont(ofSize: 16)
                lbl.numberOfLines = 0
                return lbl
            }()
            
            var height: NSLayoutConstraint?
            
            override init(frame: CGRect) {
                super.init(frame: frame)
                constraints()
            }
            required init?(coder aDecoder: NSCoder) {
                fatalError("init(coder:) has not been implemented")
            }
            
        }

        extension CustomCollectionVC {
            func constraints() {
                self.addSubview(imageView)
                self.addSubview(label)
                
                imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
                imageView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
                imageView.widthAnchor.constraint(equalToConstant: 60).isActive = true
                imageView.heightAnchor.constraint(equalToConstant: 60).isActive = true
                
                label.topAnchor.constraint(equalTo: imageView.bottomAnchor).isActive = true
                label.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
                label.widthAnchor.constraint(equalToConstant: 60).isActive = true
                height = label.heightAnchor.constraint(equalToConstant: 20)
                height?.isActive = true
            }
        }

#14

@voragomod @AlexKon спасибо за варианты!!! сегодня попробую все сделать и отпишусь