如果标签太长,我如何在结尾淡出标签而不是用“...”替换结尾/如何使用 GoogleToolboxForMac

How do I Fade Label out at end instead of replacing end with "..." if it's too long / How to use GoogleToolboxForMac

我从 GoogleToolboxForMac 找到了 GTMFadeTruncatingLabelTest 的解决方案,但我不太了解如何使用它,而且我没有找到任何相关信息

但是如果你有除此之外的其他解决方案

如果您无法通过 GoogleToolboxForMac 帮助我,请随时提出其他解决方案

结尾应该是这样的:

我不确定 GTMFadeTruncatingLabelTest,但我可以提供替代解决方案。

步骤

  1. 检查标签的文本是否将被截断
  2. 如果 1 为真,则创建一个从不透明到透明的 CAGradientLayer
  3. 将渐变图层作为蒙版应用到 UILabel

实施

如果你不想看剩下的,就grab the code from this repo

我将上面的步骤 1、2 和 3 包装在自定义 UILabel 子类中。原因在评论中解释。

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

然后你可以像普通的 UILabel 一样使用它,例如:

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

输出

限制

这种方式只支持单行UILabels

更新

添加了一个功能来删除UILabel使用此功能默认使用省略号(三个点)的截断方法。

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

此功能已在上述原始代码和 repo 中更新。