2015-03-07 18 views
6

Sto lavorando a un'app in rapido. Attualmente sto lavorando sulla popolazione di una vista tabella con celle personalizzate, vedi screenshot. Tuttavia, in questo momento ho impostato il testo in modo che il titolo sia esattamente 2 righe e il riepilogo sia esattamente 3 righe. In questo modo, il testo viene a volte troncato. Ora, voglio impostare la priorità per il testo nel titolo, in modo che se il titolo viene troncato quando è lungo 2 righe, lo espongo a 3 righe e ne compio solo 2 righe. Ho provato a farlo con il layout automatico, ma non ci sono riuscito. Ora ho provato il seguente approccio, in base a this e this, ma anche la funzione di seguito non sembrava determinare con precisione se il testo è stato troncato.Verifica del troncamento in UILabel - iOS, Swift

func isTruncated(label:UILabel) -> Bool { 
    let context = NSStringDrawingContext() 
    let text : NSAttributedString = NSAttributedString(string: label.text!, attributes: [NSFontAttributeName : label.font]) 

    let labelSize : CGSize = CGSize(width: label.frame.width, height: CGFloat.max) 


    let options : NSStringDrawingOptions = unsafeBitCast(NSStringDrawingOptions.UsesLineFragmentOrigin.rawValue | NSStringDrawingOptions.UsesFontLeading.rawValue, NSStringDrawingOptions.self) 

    let labelRect : CGRect = text.boundingRectWithSize(labelSize, options: options, context: context) 

    if Float(labelRect.height/label.font.lineHeight) > Float(label.numberOfLines) { 
     return true 
    } else { 
     return false 
    } 
} 

Qualcuno può aiutare? Come posso cambiare la mia funzione per far funzionare questo? O dovrebbe funzionare con diversi vincoli di layout automatico e come? Grazie mille!


EDIT: questo è il mio codice corrente. Il layout automatico è fatto nello storyboard, tuttavia la modifica del layout automatico viene eseguita in codice. importazione UIKit

class FeedTableViewCell: UITableViewCell { 

var thumbnailImage = UIImageView() 

@IBOutlet var titleText: UILabel! 

@IBOutlet var summaryText: UILabel! 

@IBOutlet var sourceAndDateText: UILabel! 

var imgTitleConst = NSLayoutConstraint() 
var imgSummaryConst = NSLayoutConstraint() 
var imgDetailConst = NSLayoutConstraint() 

var titleConst = NSLayoutConstraint() 
var summaryConst = NSLayoutConstraint() 
var detailConst = NSLayoutConstraint() 

var titleHeightConst = NSLayoutConstraint() 
var summaryHeightConst = NSLayoutConstraint() 


var imageRemoved = false 
var titleConstAdd = false 
override func awakeFromNib() { 
    super.awakeFromNib() 
    thumbnailImage.clipsToBounds = true 
    summaryText.clipsToBounds = true 
    titleText.clipsToBounds = true 
    sourceAndDateText.clipsToBounds = true 
    addImage() 

} 

    func removeImage() { 
    if let viewToRemove = self.viewWithTag(123) { 
     imageRemoved = true 
     viewToRemove.removeFromSuperview() 
      self.contentView.removeConstraints([imgTitleConst, imgSummaryConst, imgDetailConst]) 
     titleConst = NSLayoutConstraint(item: self.titleText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14) 

     summaryConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14) 

     detailConst = NSLayoutConstraint(item: sourceAndDateText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14) 

     self.contentView.addConstraints([titleConst, detailConst, summaryConst]) 
     setNumberOfLines() 
     self.contentView.layoutSubviews() 
    } 


} 

func addImage() { 
    thumbnailImage.tag = 123 
    thumbnailImage.image = UIImage(named: "placeholder") 
    thumbnailImage.frame = CGRectMake(14, 12, 100, 100) 
    thumbnailImage.contentMode = UIViewContentMode.ScaleAspectFill 
    thumbnailImage.clipsToBounds = true 
    self.contentView.addSubview(thumbnailImage) 

    if imageRemoved { 
     self.contentView.removeConstraints([titleConst, summaryConst, detailConst]) 
    } 


    var widthConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100) 
    var heightConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100) 
    var leftConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14) 
    var topConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 12) 



     imgTitleConst = NSLayoutConstraint(item: self.titleText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8) 

    imgSummaryConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8) 

    imgDetailConst = NSLayoutConstraint(item: sourceAndDateText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8) 


    self.contentView.addConstraints([widthConst, heightConst, leftConst, topConst, imgTitleConst, imgSummaryConst, imgDetailConst]) 
    setNumberOfLines() 
    self.contentView.layoutSubviews() 

} 




override func setSelected(selected: Bool, animated: Bool) { 
    super.setSelected(selected, animated: animated) 

    // Configure the view for the selected state 
} 

func setNumberOfLines() { 

    if titleConstAdd { 
     self.contentView.removeConstraints([titleHeightConst, summaryHeightConst]) 
    } 
    if titleText.numberOfLines == 3 { 
     titleText.numberOfLines = 2 
    } 
    if countLabelLines(titleText) > 2 { 
     titleText.numberOfLines = 3 
     summaryText.numberOfLines = 2 
     println("adjusting label heigh to be taller") 
     titleHeightConst = NSLayoutConstraint(item: titleText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 51) 
     summaryHeightConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 32) 
     self.contentView.addConstraints([titleHeightConst, summaryHeightConst]) 
    } else { 
     titleText.numberOfLines = 2 
     summaryText.numberOfLines = 3 

     titleHeightConst = NSLayoutConstraint(item: titleText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 36) 
      summaryHeightConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 47) 
     self.contentView.addConstraints([titleHeightConst, summaryHeightConst]) 
    } 

    titleConstAdd = true 


} 
} 


func countLabelLines(label:UILabel)->Int{ 

if let text = label.text{ 
    // cast text to NSString so we can use sizeWithAttributes 
    var myText = text as NSString 

    //Set attributes 
    var attributes = [NSFontAttributeName : UIFont.boldSystemFontOfSize(14)] 

    //Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another 

    var labelSize = myText.boundingRectWithSize(CGSizeMake(label.bounds.width, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributes, context: nil) 

    //Now we return the amount of lines using the ceil method 
    var lines = ceil(CGFloat(labelSize.height)/label.font.lineHeight) 
    println(labelSize.height) 
    println("\(lines)") 
    return Int(lines) 
} 

return 0 

} 

risposta

10

È possibile utilizzare il metodo sizeWithAttributes da NSString per ottenere il numero di linee vostra UILabel ha. Si dovrà lanciare il testo dell'etichetta per NSString primo ad utilizzare questo metodo:

func countLabelLines(label:UILabel)->Int{ 

    if let text = label.text{ 
     // cast text to NSString so we can use sizeWithAttributes 
     var myText = text as NSString 
     //A Paragraph that we use to set the lineBreakMode. 
     var paragraph = NSMutableParagraphStyle() 
     //Set the lineBreakMode to wordWrapping 
     paragraph.lineBreakMode = NSLineBreakMode.ByWordWrapping 

     //Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another 
     var labelSize = myText.sizeWithAttributes([NSFontAttributeName : UIFont.systemFontOfSize(17), NSParagraphStyleAttributeName : paragraph.copy()]) 

     //Now we return the amount of lines using the ceil method 
     var lines = ceil(CGFloat(size.height)/label.font.lineHeight) 
     return Int(lines) 
    } 

    return 0 

} 

Modifica

Se questo metodo non funziona per voi, perché l'etichetta non ha una larghezza fissa, è possibile utilizzare boundingRectWithSize per ottenere le dimensioni dell'etichetta e utilizzarlo con il metodo ceil.

func countLabelLines(label:UILabel)->Int{ 

    if let text = label.text{ 
     // cast text to NSString so we can use sizeWithAttributes 
     var myText = text as NSString 

     //Set attributes 
     var attributes = [NSFontAttributeName : UIFont.systemFontOfSize(UIFont.systemFontSize())] 

     //Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another 
     var labelSize = myText.boundingRectWithSize(CGSizeMake(label.bounds.width, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributes, context: nil) 

     //Now we return the amount of lines using the ceil method 
     var lines = ceil(CGFloat(labelSize.height)/label.font.lineHeight) 
     return Int(lines) 
    } 

    return 0 

} 
+0

Grazie mille, tuttavia il metodo restituisce sempre 1 per me. Penso che questo sia dovuto alla mancanza di larghezza specificata. Hai qualche modo per risolverlo? –

+0

Ho aggiunto un'altra possibilità. Lì devi usare un'altra funzione. Dovrebbe funzionare. :) – Christian

+0

Hm, grazie, quel codice dovrebbe funzionare, ma penso che in qualche modo il mio layout automatico stia lavorando contro di esso. Vedi questo [screenshot] (https://www.dropbox.com/s/ioocjbziyfmkxu7/iOS%20Simulator%20Screen%20Shot%2008%20Mar%202015%2014.14.42.png?dl=0), in cui alcune celle che non serve più spazio sono allocati più spazi e alcune celle che hanno bisogno di più spazio non hanno più spazio. Ho controllato, e ha qualcosa a che fare con la funzione per calcolare l'altezza. Forse i limiti dell'etichetta non sono accurati in qualche modo? Ho modificato il mio post originale con il mio codice per la cella tableView. Grazie per l'aiuto! –

2

Questo funziona per etichette con larghezza fissa e il numero fisso di linee o altezza fissa:

extension UILabel { 
    func willBeTruncated() -> Bool { 
     let label:UILabel = UILabel(frame: CGRectMake(0, 0, self.bounds.width, CGFloat.max)) 
     label.numberOfLines = 0 
     label.lineBreakMode = NSLineBreakMode.ByWordWrapping 
     label.font = self.font 
     label.text = self.text 
     label.sizeToFit() 
     if label.frame.height > self.frame.height { 
      return true 
     } 
     return false 
    } 
} 
+0

Funzionerà solo se l'etichetta è stata renderizzata con il passaggio di layout! – StackUnderflow

4

Swift 3

Una soluzione semplice conta il numero di righe dopo l'assegnazione del stringa e confronta il numero massimo di righe dell'etichetta.

import Foundation 
import UIKit 

extension UILabel { 

    func countLabelLines() -> Int { 
     // Call self.layoutIfNeeded() if your view is uses auto layout 
     let myText = self.text! as NSString 
     let attributes = [NSFontAttributeName : self.font] 

     let labelSize = myText.boundingRect(with: CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil) 
     return Int(ceil(CGFloat(labelSize.height)/self.font.lineHeight)) 
    } 

    func isTruncated() -> Bool { 

     if (self.countLabelLines() > self.numberOfLines) { 
      return true 
     } 
     return false 
    } 
} 
+0

Funzionerà solo se l'etichetta è stata renderizzata con il passaggio di layout! – StackUnderflow