简体   繁体   English

设置收集视图单元格的动态宽度时出现问题

[英]issue while set dynamic width of collection view cell

I am trying to dynamically set the width of collection view cell. 我试图动态设置集合视图单元格的宽度。 Initially it's not rendering as expected. 最初,它没有按预期方式渲染。 But when I tap on the cell, its getting adjusted as I want. 但是,当我点击该单元格时,它会根据需要进行调整。 Here's the code that I wrote: 这是我编写的代码:

Code

import UIKit

class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {

    @IBOutlet weak var collView: UICollectionView!


    var tasksArray = ["To Do", "SHOPPING","WORK"]
    var selectedIndex = Int()

    override func viewDidLoad() {
        super.viewDidLoad()
        let layout = collView?.collectionViewLayout as! UICollectionViewFlowLayout
        layout.itemSize = UICollectionViewFlowLayout.automaticSize
        layout.estimatedItemSize = CGSize(width: 93, height: 40)
        // Do any additional setup after loading the view, typically from a nib.
    }
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return tasksArray.count
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
        cell.lblName.text = tasksArray[indexPath.row]
        if selectedIndex == indexPath.row
        {
            cell.backgroundColor = UIColor.lightGray
        }
        else
        {
            cell.backgroundColor = UIColor.white
        }
        cell.layer.borderWidth = 1
        cell.layer.cornerRadius = cell.frame.height / 2
        return cell
    }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        selectedIndex = indexPath.row
        self.collView.reloadData()
    }
}

here i am attaching two image before tapping and after tapping so you can easily understood 在这里,我在点击之前和之后都附加了两个图像,因此您可以轻松理解

[![Here is the image before i tap [![这是我点击之前的图像

这是在点击单元格后给我完美的结果 on cell] 2 ] 2 在单元格上] 2 ] 2

so please tell me whats wrong in my code 所以请告诉我我的代码有什么问题

I have found a small trick for swift 4.2 我发现了一个快速4.2的小技巧

For dynamic width & fixed height: 对于动态宽度和固定高度:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let label = UILabel(frame: CGRect.zero)
    label.text = textArray[indexPath.item]
    label.sizeToFit()
    return CGSize(width: label.frame.width, height: 32)
}

Inside your CollectionViewCell override preferredLayoutAttributesFitting function This is where the cell has a chance to indicate its preferred attributes, including size, which we calculate using auto layout. CollectionViewCell内部,重写preferredLayoutAttributesFitting函数,这是单元格在其中指示其首选属性(包括尺寸)的位置,我们可以使用自动布局计算这些属性。

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

It is obvious that you have to use sizeForItemAt flow layout delegate in order to pass the dynamic width. 显然,必须使用sizeForItemAt流布局委托才能传递动态宽度。 But the tricky part is to calculate the width of the cell based on the text. 但是棘手的部分是根据文本计算单元格的宽度。 You can actually calculate the width of a text given that you have a font. 只要有字体,就可以实际计算文本的宽度。

Let's introduce few extension which will help us along the way 让我们介绍一些扩展,这将对我们有帮助

StringExtensions.swift StringExtensions.swift

extension String {

    public func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constraintRect,
                                        options: .usesLineFragmentOrigin,
                                        attributes: [.font: font], context: nil)

        return ceil(boundingBox.width)
    }
}

This method let us know the width of a string, if i provide it the height and the font. 如果我提供字符串的高度和字体,则此方法让我们知道字符串的宽度。 Then use it inside sizeForItem as follows 然后在sizeForItem内部使用它,如下所示

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let height = 40
    let text = YOUR_TEXT
    let width = text.width(withConstrainedHeight: height, font: Font.regular.withSize(.extraSmall)) + EXTRA_SPACES_FOR_LEFT_RIGHT_PADDING
    return CGSize(width: width, height: height)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM