iOS UILabel autoshrink so word doesn't truncate to two lines

前端 未结 4 377
陌清茗
陌清茗 2020-12-11 06:35

I\'m trying to have the UILabel shrink so that words don\'t truncate to the next line. Not just text truncating at the end of the text area.

If I have a box that is

相关标签:
4条回答
  • 2020-12-11 07:30

    Just to add Swift 4 version + Add a guard to do it only with adjustsFontSizeToFitWidth true, as user using false won't want to fit by long word I guess.

    extension UILabel {
    // Adjusts the font size to avoid long word to be wrapped
    func fitToAvoidWordWrapping() {
        guard adjustsFontSizeToFitWidth else {
            return // Adjust font only if width fit is needed
        }
        guard let words = text?.components(separatedBy: " ") else {
            return // Get array of words separate by spaces
        }
    
        // I will need to find the largest word and its width in points
        var largestWord: NSString = ""
        var largestWordWidth: CGFloat = 0
    
        // Iterate over the words to find the largest one
        for word in words {
            // Get the width of the word given the actual font of the label
            let wordWidth = word.size(withAttributes: [.font: font]).width
    
            // check if this word is the largest one
            if wordWidth > largestWordWidth {
                largestWordWidth = wordWidth
                largestWord = word as NSString
            }
        }
    
        // Now that I have the largest word, reduce the label's font size until it fits
        while largestWordWidth > bounds.width && font.pointSize > 1 {
            // Reduce font and update largest word's width
            font = font.withSize(font.pointSize - 1)
            largestWordWidth = largestWord.size(withAttributes: [.font: font]).width
        }
    }
    }
    
    0 讨论(0)
  • 2020-12-11 07:35

    I can think of nothing that's directly built in. So I'd suggest:

    Split the string into components by [NSCharacterSet +whitespaceAndNewlineCharacterSet] and [NSString -componentsSeparatedByCharactersInSet:]. I considered recommending the higher-level NSLinguisticTagger to get out whole words but that wouldn't allow for things like words with a colon on the end.

    Of those words, find the typographically largest using the UIKit addition NSString -sizeWithAttributes: (under iOS 7) or -sizeWithFont: (under 6 or below). You're going to make the assumption that the largest will remain the largest as you scale the font size down, which I think will always be true because Apple doesn't do aggressive font hinting.

    If that word is already less wide than your view's width, you're done. Just show the string.

    Otherwise use a quick binary search, repeatedly querying the size, until you find the smaller font size that you need to within whatever precision you think is appropriate (0.1 of a point sounds reasonable to me but you get the point). Then show the whole string at that size.

    0 讨论(0)
  • 2020-12-11 07:35

    I made a Swift extension of UILabel. Just call the method to the label after bounds and text are set.

    extension UILabel {
    
    func fitToAvoidWordWrapping(){
        // adjusts the font size to avoid long word to be wrapped
    
        // get text as NSString
        let text = self.text ?? "" as NSString
    
        // get array of words separate by spaces
        let words = text.componentsSeparatedByString(" ") as! [NSString]
    
        // I will need to find the largest word and its width in points
        var largestWord : NSString = ""
        var largestWordWidth : CGFloat = 0
    
        // iterate over the words to find the largest one
        for word in words{
    
            // get the width of the word given the actual font of the label
            let wordSize = word.sizeWithAttributes([NSFontAttributeName : self.font])
            let wordWidth = wordSize.width
    
            // check if this word is the largest one
            if wordWidth > largestWordWidth{
            largestWordWidth = wordWidth
            largestWord = word
            }
        }
    
        // now that I have the largest word, reduce the label's font size until it fits
        while largestWordWidth > self.bounds.width && self.font.pointSize > 1{
    
            // reduce font and update largest word's width
            self.font = self.font.fontWithSize(self.font.pointSize - 1)
            let largestWordSize = largestWord.sizeWithAttributes([NSFontAttributeName : self.font])
            largestWordWidth = largestWordSize.width
        }
    }
    } 
    
    0 讨论(0)
  • 2020-12-11 07:35

    SWIFT 3 translation of above extension. Works like a charm!

    extension UILabel {
    
    func fitToAvoidWordWrapping(){
        // adjusts the font size to avoid long word to be wrapped
    
        // get text as NSString
        let text = self.text ?? ("" as NSString) as String
    
        // get array of words separate by spaces
        let words = text.components(separatedBy: " ")
    
        // I will need to find the largest word and its width in points
        var largestWord : NSString = ""
        var largestWordWidth : CGFloat = 0
    
        // iterate over the words to find the largest one
        for word in words{
    
            // get the width of the word given the actual font of the label
            let wordSize = word.size(attributes: [NSFontAttributeName : self.font])
            let wordWidth = wordSize.width
    
            // check if this word is the largest one
            if wordWidth > largestWordWidth{
                largestWordWidth = wordWidth
                largestWord = word as NSString
            }
        }
    
        // now that I have the largest word, reduce the label's font size until it fits
        while largestWordWidth > self.bounds.width && self.font.pointSize > 1{
    
            // reduce font and update largest word's width
            self.font = self.font.withSize(self.font.pointSize - 1)
            let largestWordSize = largestWord.size(attributes: [NSFontAttributeName : self.font])
            largestWordWidth = largestWordSize.width
        }
    }
    }
    
    0 讨论(0)
提交回复
热议问题