Друзья, сижу бьюсь, как сделать высоту UICollectionViewCell по размеру содержимого. В ячейке есть многострочный UILabel. Если текста много - ячейка не растягивается по высоте.
Высота UICollectionViewCell по размеру содержимого
Мне кажется вы не правильно понимаете как это работает.
Растягиваете вой CollectionView как вам нужно, в ячейку вставляете ScrollView, растягиваете его на всю ячейку, дальше уже свой контент вставляете в ScrollView. В таком случае контент больше ячейки, будет в нем скролиться.
Если же у вас вертикальная прокрутка, тогда уже лучше использовать TableView.
А можно ли в TableView сделать так, чтобы было расстояние между ячейками, а не вплотную? Да, мне нужна вертикальная прокрутка, но ячейки должны быть отделены друг от друга.
Как один из вариантов, выставить внутренний padding у ячеек.
Не совсем уверен, но может быть можно как-то сделать это с помощью разделителя, указав ему большую толщину и сделать прозрачным.
Я все же использовал UICollectionView. Чуть позже выложу решение, когда будет доступ к ноуту.
Если тебе просто нужно изменить размер ячейки под размер текста, можно использовать метод
boundingRect(with:options:attributes:) класса NSString
Он возвращает CGRect, узнаешь высоту текста если у тебя ширина задана константно и соотвественно переопределись метод
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
Попробуй сделать кастовую ячейку и там укажи constrains для imageview и для label, у тебя картинка везде скорее всего будет одинакова, ширина label тоже ограничена шириной картинки, а высоту посчитаешь boundingRect(with:options:attributes:) вот так я бы начал делать.
А ячейка просто будет включать два объекта
Я использовал свой класс для ячейки 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
}
Примерно так я себе это представляю
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
}
}