【问题标题】:Check for Truncation in UILabel - iOS, Swift检查 UILabel 中的截断 - iOS,Swift
【发布时间】:2015-05-09 08:27:45
【问题描述】:

我正在快速开发一个应用程序。目前,我正在使用自定义单元格填充表格视图,请参阅screenshot。但是,现在我设置了文本,标题正好是 2 行,摘要正好是 3 行。通过这样做,文本有时会被截断。现在,我想为标题中的文本设置优先级,这样如果标题在 2 行长时被截断,我将其扩展为 3 行并使摘要仅 2 行。我尝试使用自动布局来执行此操作,但失败了。现在我尝试了以下方法,根据thisthis,但是下面的函数似乎也不能准确地确定文本是否被截断。

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

有人可以帮忙吗?如何更改我的功能以使其正常工作?或者应该使用不同的自动布局约束以及如何使用? 非常感谢!


编辑: 这是我当前的代码。一些自动布局是在情节提要中完成的,但是改变自动布局是在代码中完成的。 导入 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

}

【问题讨论】:

    标签: ios cocoa-touch swift autolayout uilabel


    【解决方案1】:

    您可以使用NSString 中的sizeWithAttributes 方法来获取您的UILabel 的行数。您必须先将标签文本转换为 NSString 才能使用此方法:

    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
    
    }
    

    编辑

    如果此方法对您不起作用,因为您的标签没有固定宽度,您可以使用 boundingRectWithSize 来获取标签的大小并将其与 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
    
    }
    

    【讨论】:

    • 非常感谢,但是该方法总是为我返回 1。我认为这是因为没有指定宽度。你有什么办法解决吗?
    • 我添加了另一种可能性。在那里你必须使用另一个功能。它应该工作。 :)
    • 嗯,谢谢,该代码应该可以工作,但我认为不知何故我的自动布局正在反对它。请参阅此screenshot,其中一些不需要更多空间的单元被分配了更多空间,而一些确实需要更多空间的单元没有分配更多空间。我查过了,它与计算高度的函数有关。也许标签边界不准确?我已经使用 tableView 单元格的代码编辑了我的原始帖子。感谢您的帮助!
    • 这只有在标签已经使用布局通道渲染时才有效!
    【解决方案2】:

    斯威夫特 3

    一个简单的解决方案是在分配字符串后计算行数并与标签的最大行数进行比较。

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

    【讨论】:

    • 这只有在标签已经使用布局通道渲染时才有效!
    【解决方案3】:

    这适用于具有固定宽度和固定行数或固定高度的标签:

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

    【讨论】:

    • 这只有在标签已经使用布局通道渲染时才有效!
    猜你喜欢
    • 2011-03-05
    • 2012-08-16
    • 2014-02-15
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多