skip to Main Content

I’ve found a solution with GTMFadeTruncatingLabelTest from GoogleToolboxForMac but don’t really understand how to use it and I don’t find anything about it

but if you have another solution besides of this one

If you can’t help me with GoogleToolboxForMac feel free to suggest other solution

Should kinda look like this at the end:

image

2

Answers


  1. I am not sure about the GTMFadeTruncatingLabelTest but I can offer an alternative solution.

    Steps

    1. Check if the label’s text is going to be truncated
    2. If 1 is true, Create a CAGradientLayer that goes from Opaque to Transparent
    3. Apply the gradient layer as a mask to the UILabel

    Implementation

    If you don’t want to read the rest, just grab the code from this repo

    I wrapped step 1, 2 and 3 from above in a custom UILabel subclass. The reasoning is explained in the comments.

    class FadingLabel: UILabel
    {
        // Add a property observer for text changes
        // as we might not need to fade anymore
        override var text: String?
        {
            didSet
            {
                // Check if the text needs to be faded
                fadeTailIfRequired()
            }
        }
        
        // Add a property observer for numberOfLines changes
        // as only 1 line labels are supported for now
        override var numberOfLines: Int
        {
            didSet
            {
                // Reset the number of lines to 1
                if numberOfLines != 1
                {
                    numberOfLines = 1
                }
            }
        }
        
        override func layoutSubviews()
        {
            super.layoutSubviews()
            
            // The label's frame might have changed so check
            // if the text needs to be faded or not
            fadeTailIfRequired()
        }
        
        
        /// The function that handles fading the tail end of the text if the text goes
        /// beyond the bounds of the label's width
        private func fadeTailIfRequired()
        {
            // Reset the numberOfLines to 1
            numberOfLines = 1
            
            // Prevent processing fading when the library is in the middle of
            // processing the string to truncate the ellipsis
            if !isTruncatingEllipsis
            {
                // Check if the label's has it's width set and if the text goes
                // beyond it's width plus a margin of safety
                if bounds.width > CGFloat.zero && intrinsicContentSize.width > bounds.width + 5
                {
                    // Fade label works better with this setting
                    allowsDefaultTighteningForTruncation = true
                    
                    // Initialize and configure a gradient to start at the end of
                    // the label
                    let gradient = CAGradientLayer()
                    gradient.frame = bounds
                    gradient.colors = [UIColor.white.cgColor, UIColor.clear.cgColor]
                    gradient.startPoint = CGPoint(x: 0.8, y: 0.5)
                    gradient.endPoint = CGPoint(x: 0.99, y: 0.5)
                    
                    // Apply the gradient as a mask to the UILabel
                    layer.mask = gradient
                    
                    // Remove ellipsis added as the default UILabel truncation character
                    removeEllipsis()
                    
                    // We do not need to go beyond this point
                    return
                }
                
                // If the text has not been truncated, remove the gradient mask
                if originalText == text
                {
                    // Remove the layer mask
                    layer.mask = nil
                }
            }
        }
        
        /// Keep removing 1 character from the label till it no longer needs to truncate
        private func removeEllipsis()
        {
            isTruncatingEllipsis = true
            
            // Keep looping till we do not have the perfect string length
            // to fit into the label
            while intrinsicContentSize.width > bounds.width
            {
                // Drop the last character
                text = String(text!.dropLast())
            }
            
            isTruncatingEllipsis = false
        }
    }
    

    Then you can use it like a regular UILabel, for example:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let fadingLabelWithLongText = FadingLabel()
        view.addSubview(fadingLabelWithLongText)
        fadingLabelWithLongText.text = "Fading label with text more than it's bounds can handle"
        fadingLabelWithLongText.textColor = .white
        fadingLabelWithLongText.frame = CGRect(x: 20, y: 90, width: 250, height: 50)
        
        let regularLabelWithLongText = UILabel()
        view.addSubview(regularLabelWithLongText)
        regularLabelWithLongText.text = "Regular label with text more than it's bounds can handle"
        regularLabelWithLongText.textColor = .white
        regularLabelWithLongText.frame = CGRect(x: 20, y: 160, width: 250, height: 50)
        
        let fadingLabelWithShortText = UILabel()
        view.addSubview(fadingLabelWithShortText)
        fadingLabelWithShortText.text = "Fading label with text that fits"
        fadingLabelWithShortText.textColor = .white
        fadingLabelWithShortText.frame = CGRect(x: 20, y: 230, width: 250, height: 50)
        
        let regularLabelWithShortText = UILabel()
        view.addSubview(regularLabelWithShortText)
        regularLabelWithShortText.text = "Regular label with text that fits"
        regularLabelWithShortText.textColor = .white
        regularLabelWithShortText.frame = CGRect(x: 20, y: 300, width: 250, height: 50)
    }
    

    Output

    Custom UILabel with fade truncated text

    Limitation

    This way only supports single line UILabels

    Update

    Added a function to remove the default truncation method of using ellipsis (three dots) by UILabel with this function.

    /// Keep removing 1 character from the label till it no longer needs to truncate
    private func removeEllipsis()
    {
        isTruncatingEllipsis = true
        
        // Keep looping till we do not have the perfect string length
        // to fit into the label
        while intrinsicContentSize.width > bounds.width
        {
            // Drop the last character
            text = String(text!.dropLast())
        }
        
        isTruncatingEllipsis = false
    }
    

    This function has been updated in the original code and repo mentioned above.

    Login or Signup to reply.
  2. I Think the easiest way is to use the following code:

    titleLabel.adjustsFontSizeToFitWidth = false
    titleLabel.lineBreakMode = .byClipping
    

    It automatically fades the last words if applicable and text size has more width than UILabel!

    thanks to thi

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search