web-dev-qa-db-fra.com

Hauteur de cellule dynamique CollectionView swift

J'essaie de créer une vue de collection avec des cellules affichant une chaîne de longueur variable.

J'utilise cette fonction pour définir la disposition des cellules:

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

ce que j'aimerais faire, c'est manipuler cellSize.height basé sur mon cell.labelString.utf16Count longueur. la logique de base serait de sa que

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

Cependant, je ne parviens pas à récupérer la longueur de chaîne de mon étiquette de cellule qui renvoie toujours la valeur nil. (Je pense que ce n'est pas encore chargé ...

pour une meilleure compréhension, voici le code complet:

// 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
    }
29
SKYnine

Vous pouvez définir de manière dynamique le cadre de la cellule dans la fonction cellForItemAtIndexPath afin de personnaliser la hauteur en fonction d'une étiquette si vous ignorez la fonction sizeForItemAtIndexPath. Avec la personnalisation de la taille, vous devrez probablement vous pencher sur le flux de présentation de la vue Collection, mais espérons que cela vous oriente dans la bonne direction. Cela peut ressembler à quelque chose comme ça:

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

qui donne des hauteurs dynamiques comme si enter image description here

17
Ian

Bien que la réponse ci-dessus puisse résoudre votre problème, elle établit une manière assez rudimentaire d’affecter la hauteur de chaque cellule. Vous êtes obligé de coder en dur chaque hauteur de cellule en vous basant sur une estimation. Une meilleure façon de traiter ce problème consiste à définir la hauteur de chaque cellule dans la méthode sizeForItemAtIndexPath delegate de la collectionview.

Je vais vous expliquer les étapes à suivre ci-dessous.

Étape 1: Améliorez votre classe UICollectionViewDelegateFlowLayout

Étape 2: Créez une fonction pour estimer la taille de votre texte: Cette méthode renverra une valeur de hauteur qui conviendra à votre chaîne!

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

Étape 3: Utilisez ou substituez la méthode déléguée ci-dessous:

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's height
    if let text = array?[indexPath.item].text {
         height = estimateFrameForText(text).height + padding
    }
    return CGSize(width: yourDesiredWidth, height: height)
}
21
Eli Whittle

Dans Swift 3, utilisez la méthode ci-dessous:

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()
    }
}
7
Manpreet Singh