2015-03-07 3 views
6

Ich arbeite an einer App in Swift. Derzeit arbeite ich an der Auffüllung einer Tabellenansicht mit benutzerdefinierten Zellen, siehe screenshot. Allerdings habe ich jetzt den Text so eingestellt, dass der Titel genau 2 Zeilen lang ist und die Zusammenfassung genau 3 Zeilen ist. Dadurch wird der Text manchmal abgeschnitten. Jetzt möchte ich die Priorität für Text im Titel festlegen, so dass, wenn der Titel abgeschnitten wird, wenn es 2 Zeilen lang ist, ich es auf 3 Zeilen erweitern und die Zusammenfassung nur 2 Zeilen machen. Ich habe versucht, dies mit Auto-Layout, aber gescheitert. Jetzt versuchte ich den folgenden Ansatz, nach this und this, aber die Funktion unten schien auch nicht genau zu bestimmen, ob der Text abgeschnitten ist.Suchen nach Abschneiden 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 
    } 
} 

Kann jemand helfen? Wie kann ich meine Funktion ändern, damit dies funktioniert? Oder sollte mit verschiedenen Auto-Layout-Einschränkungen arbeiten und wie? Vielen Dank!


EDIT: dies mein aktueller Code ist. Ein gewisses automatisches Layout ist das Storyboard, jedoch wird das sich ändernde automatische Layout im Code ausgeführt. Import 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 

} 

Antwort

10

Sie können die sizeWithAttributes Methode von NSString verwenden, um die Anzahl der Zeilen, um Ihre UILabel hat. Sie werden Ihr Beschriftungstext NSString werfen den ersten Einsatz dieser Methode müssen:

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 

} 

bearbeiten

Wenn diese Methode nicht für Sie arbeiten, weil das Etikett nicht eine feste Breite hat, Sie kann boundingRectWithSize verwenden, um die Größe des Etiketts zu erhalten und dieses mit der ceil-Methode zu verwenden.

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

Vielen Dank, aber die Methode gibt immer 1 für mich zurück. Ich denke, das liegt daran, dass keine Breite angegeben ist. Hast du einen Weg, das zu lösen? –

+0

Ich habe eine andere Möglichkeit hinzugefügt. Dort müssen Sie eine andere Funktion verwenden. Es sollte funktionieren. :) – Christian

+0

Hm, danke, dieser Code sollte funktionieren, aber ich denke, dass irgendwie mein Auto-Layout dagegen arbeitet. Sehen Sie dies [Screenshot] (https://www.dropbox.com/s/ioocjbziyfmkxu7/iOS%20Simulator%20Screen%20Shot%2008%20Mar%202015%2014.14.42.png?dl=0), in dem einige Zellen, die Sie benötigen nicht mehr Platz, sie haben mehr Platz und einige Zellen, die mehr Platz benötigen, haben keinen Platz mehr. Ich habe überprüft, und es hat etwas mit der Funktion zu tun, um die Höhe zu berechnen. Vielleicht sind die Etikettengrenzen irgendwie nicht genau? Ich habe meinen ursprünglichen Post mit meinem Code für die TableView-Zelle bearbeitet. Danke für Ihre Hilfe! –

2

Diese für Etiketten mit fester Breite und die festgelegte Anzahl von Zeilen oder festen Höhe arbeitet:

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

Dies funktioniert nur, wenn das Label mit dem Layout-Pass gerendert wurde! – StackUnderflow

4

Swift 3

Eine einfache Lösung ist, Zählen der Anzahl von Zeilen nach dem Zuweisen string und vergleiche die maximale Anzahl der Zeilen des Labels.

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

Dies funktioniert nur, wenn das Etikett mit dem Layout-Durchlauf gerendert wurde! – StackUnderflow