2014-12-04 10 views
20

Sto cercando di creare una vista collezione con celle che visualizzano stringhe con lunghezza variabile.CollectionView Dynamic cell height swift

im utilizzando questa funzione per impostare il layout delle cellule:

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

quello che vorrei fare è manipolare cellSize.height in base alla mia cell.labelString.utf16Count lunghezza. la logica di base sarebbe quella di Sa che

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

Tuttavia, non riesco a recuperare la mia etichetta cellule lunghezza della stringa che restituisce sempre zero. (Penso che non è ancora caricato ...

per una migliore comprensione, ecco il codice completo:

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

risposta

11

È possibile impostare in modo dinamico il telaio della cella in funzione cellForItemAtIndexPath, in modo da poter personalizzare il altezza basata su un'etichetta se si ignora la funzione sizeForItemAtIndexPath. Con la personalizzazione della dimensione, è probabile che si debba esaminare il flusso del layout della vista raccolta, ma si spera che questo punti nella giusta direzione. Può essere qualcosa del genere:

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

che dà altezze dinamiche come enter image description here

+0

Impressionante, ho esplorato diversi modi per risolvere questo problema, ma Non ho guardato a fare questo nel cellForItemAtIndexPath. Grazie per i suggerimenti ti farò sapere! – SKYnine

+1

Ok sembra che io possa adattare l'altezza usando il tuo metodo ma ora il mio problema diventa la spaziatura tra le righe. Ho uno spazio importante di cui non ho bisogno. Tutte le mie impostazioni sono impostate su zero nello storyboard – SKYnine

+0

heights [indexPath.row] si tratta di oggetto dati server. Puoi dirmi per favore. – Malleswari

15

Mentre la risposta sopra può risolvere il tuo problema, stabilisce un modo piuttosto crudo di assegnare l'altezza di ogni cella. Sei costretto a codificare in modo rigido ogni altezza della cella in base a una stima. Un modo migliore per gestire questo problema è impostare l'altezza di ogni cella nel metodo delegato sizeForItemAtIndexPath della collectionview.

Ti guiderò attraverso i passaggi su come eseguire questa operazione di seguito.

Fase 1: Fai la tua classe di estendere UICollectionViewDelegateFlowLayout

Fase 2: Creazione di una funzione per stimare la dimensione del testo: Questo metodo restituisce un valore di altezza che si adatta al stringa!

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

Fase 3: utilizzare o ignorare metodo delegato di seguito:

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

Metodo .boundingRectWithSize sembra non funzionare bene con swift 3 e ios 10. Il calcolo è diverso su diverse dimensioni dello schermo e, soprattutto, calcola troppa altezza per il testo – virusss8

+1

Grazie mille. Ho cercato di capirlo per un po 'e nessuno degli esempi che ho visto ha sottolineato abbastanza chiaramente che è necessario estendere UICollectionViewDelegateFlowLayout. –

+0

Nessun problema, felice che tu l'abbia capito. –

6

In Swift 3, utilizzare il seguente metodo:

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() 
    } 
} 
+0

Dove stai chiamando questo metodo? –

+1

Ho chiamato questo metodo nel metodo numero di righe in modo che ogni volta crei l'altezza per la riga. Inoltre, puoi chiamarlo sul metodo di modifica dell'orientamento e chiamare la vista della raccolta di ricarica. –