Decrease the width of the last line in multiline UILabel

前端 未结 6 1918
谎友^
谎友^ 2020-12-04 18:19

I am implemententing a \"read more\" functionality much like the one in Apple\'s AppStore. However, I am using a multiline UILabel. Looking at Apple\'s AppStore

6条回答
  •  没有蜡笔的小新
    2020-12-04 18:51

    Since this post is from 2013, I wanted to give my Swift implementation of the very nice solution from @rdelmar.

    Considering we are using a SubClass of UILabel:

    private let kNumberOfLines = 2
    private let ellipsis = " MORE"
    
    private var originalString: String! // Store the original text in the init
    
    private func getTruncatingText() -> String {
        var truncatedString = originalString.mutableCopy() as! String
    
        if numberOfLinesNeeded(truncatedString) > kNumberOfLines {
            truncatedString += ellipsis
    
            var range = Range(
                start: truncatedString.endIndex.advancedBy(-(ellipsis.characters.count + 1)),
                end: truncatedString.endIndex.advancedBy(-ellipsis.characters.count)
            )
    
            while numberOfLinesNeeded(truncatedString) > kNumberOfLines {
                truncatedString.removeRange(range)
    
                range.startIndex = range.startIndex.advancedBy(-1)
                range.endIndex = range.endIndex.advancedBy(-1)
            }
        }
    
        return truncatedString
    }
    
    private func getHeightForString(str: String) -> CGFloat {
        return str.boundingRectWithSize(
            CGSizeMake(self.bounds.size.width, CGFloat.max),
            options: [.UsesLineFragmentOrigin, .UsesFontLeading],
            attributes: [NSFontAttributeName: font],
            context: nil).height
    }
    
    private func numberOfLinesNeeded(s: String) -> Int {
        let oneLineHeight = "A".sizeWithAttributes([NSFontAttributeName: font]).height
        let totalHeight = getHeightForString(s)
        return Int(totalHeight / oneLineHeight)
    }
    
    func expend() {
        var labelFrame = self.frame
        labelFrame.size.height = getHeightForString(originalString)
        self.frame = labelFrame
        self.text = originalString
    }
    
    func collapse() {
        let truncatedText = getTruncatingText()
        var labelFrame = self.frame
        labelFrame.size.height = getHeightForString(truncatedText)
        self.frame = labelFrame
        self.text = truncatedText
    }
    

    Unlike the old solution, this will work as well for any kind of text attribute (like NSParagraphStyleAttributeName).

    Please feel free to critic and comment. Thanks again to @rdelmar.

提交回复
热议问题