Подтвердить что ты не робот

CollectionView Динамическая высота ячейки swift

Im пытается создать представление коллекции с ячейками, отображающими строку с переменной длиной.

Я использую эту функцию для установки раскладки ячеек:

 func collectionView(collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath) -> CGSize
    {
        var cellSize:CGSize = CGSizeMake(self.whyCollectionView.frame.width, 86)
        return cellSize
    }

то, что я хотел бы сделать, это манипулировать cellSize.height на основе длины cell.labelString.utf16Count. основная логика заключалась бы в том, что

if((cell.labelString.text) > 70){
   cellSize.height = x
}
else{
   cellSize.height = y
}

Однако мне не удается получить длину строки метки метки ячейки, которая всегда возвращает нуль. (Я думаю, что он еще не загружен...

для лучшего понимания, вот полный код:

// WhyCell section
    var whyData:NSMutableArray! = NSMutableArray()
    var textLength:Int!
    @IBOutlet weak var whyCollectionView: UICollectionView!

//Loading data
    @IBAction func loadData() {
        whyData.removeAllObjects()

        var findWhyData:PFQuery = PFQuery(className: "PlacesWhy")
        findWhyData.whereKey("placeName", equalTo: placeName)

        findWhyData.findObjectsInBackgroundWithBlock({
            (objects:[AnyObject]!,error:NSError!)->Void in

            if (error == nil) {
                for object in objects {
                    self.whyData.addObject(object)
                }

                let array:NSArray = self.whyData.reverseObjectEnumerator().allObjects
                self.whyData = array.mutableCopy() as NSMutableArray

                self.whyCollectionView.reloadData()
                println("loadData completed. datacount is \(self.whyData.count)")
            }
        })
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.loadData()


    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return whyData.count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell:whyCollectionViewCell = whyCollectionView.dequeueReusableCellWithReuseIdentifier("whyCell", forIndexPath: indexPath) as whyCollectionViewCell

        // Loading content from NSMutableArray to cell
        let therew:PFObject = self.whyData.objectAtIndex(indexPath.row) as PFObject
        cell.userWhy.text = therew.objectForKey("why") as String!
        textLength = (therew.objectForKey("why") as String!).utf16Count
        self.whyCollectionView.layoutSubviews()

        // Displaying user information
        var whatUser:PFQuery = PFUser.query()
        whatUser.whereKey("objectId", equalTo: therew.objectForKey("reasonGivenBy").objectId)

        whatUser.findObjectsInBackgroundWithBlock({
            (objects: [AnyObject]!, error: NSError!)->Void in

            if !(error != nil) {
                if let user:PFUser = (objects as NSArray).lastObject as? PFUser {
                    cell.userName.text = user.username
                    // TODO Display avatar
                }

            }
        })

        return cell
    }

    func collectionView(collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath) -> CGSize
    {
        var cellSize:CGSize = CGSizeMake(self.whyCollectionView.frame.width, 86)
        return cellSize
    }
4b9b3361

Ответ 1

Вы можете динамически установить кадр ячейки в функции cellForItemAtIndexPath, поэтому вы можете настроить высоту на основе метки, если не учитывать функцию sizeForItemAtIndexPath. При настройке размера вам, вероятно, придется искать поток макета коллекции, но, надеюсь, это указывает на то, что вы в правильном направлении. Это может выглядеть примерно так:

class CollectionViewController: UICollectionViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    var array = ["a","as","asd","asdf","asdfg","asdfgh","asdfghjk","asdfghjklas","asdfghjkl","asdghjklkjhgfdsa"]
    var heights = [10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,90.0,100.0,110.0] as [CGFloat]

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return array.count
    }

    override func collectionView(collectionView: UICollectionView,
        cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

            let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CellID", forIndexPath: indexPath) as Cell
            cell.textLabel.text = array[indexPath.row]
            cell.textLabel.sizeToFit()

            // Customize cell height
            cell.frame = CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, heights[indexPath.row])
            return cell
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        return CGSizeMake(64, 64)
    }
}

который дает динамические высоты enter image description here

Ответ 2

В то время как ответ выше может решить вашу проблему, он устанавливает довольно грубый способ присвоения каждой высоты ячеек. Вы вынуждены жестко кодировать каждую высоту ячейки на основе некоторой оценки. Лучший способ справиться с этой проблемой - установить высоту каждой ячейки в методе делегата collectionview sizeForItemAtIndexPath.

Я расскажу вам, как это сделать ниже.

Шаг 1. Сделайте расширение класса UICollectionViewDelegateFlowLayout

Шаг 2. Создайте функцию для оценки размера вашего текста: этот метод вернет значение высоты, соответствующее вашей строке!

private func estimateFrameForText(text: String) -> CGRect {
    //we make the height arbitrarily large so we don't undershoot height in calculation
    let height: CGFloat = <arbitrarilyLargeValue>

    let size = CGSize(width: yourDesiredWidth, height: height)
    let options = NSStringDrawingOptions.UsesFontLeading.union(.UsesLineFragmentOrigin)
    let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(18, weight: UIFontWeightLight)]

    return NSString(string: text).boundingRectWithSize(size, options: options, attributes: attributes, context: nil)
}

Шаг 3: Используйте или переопределите метод делегирования ниже:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    var height: CGFloat = <someArbitraryValue>

   //we are just measuring height so we add a padding constant to give the label some room to breathe! 
    var padding: CGFloat = <someArbitraryPaddingValue>

    //estimate each cell height
    if let text = array?[indexPath.item].text {
         height = estimateFrameForText(text).height + padding
    }
    return CGSize(width: yourDesiredWidth, height: height)
}

Ответ 3

В Swift 3 используйте следующий метод:

private func updateCollectionViewLayout(with size: CGSize) {
    var margin : CGFloat = 0;
    if isIPad {
        margin = 10
    }
    else{
        margin = 6
        /* if UIDevice.current.type == .iPhone6plus || UIDevice.current.type == .iPhone6Splus || UIDevice.current.type == .simulator{
         margin = 10

         }
         */
    }
    if let layout = menuCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
        layout.itemSize = CGSize(width:(self.view.frame.width/2)-margin, height:((self.view.frame.height-64)/4)-3)
        layout.invalidateLayout()
    }
}