Swift 带有渐变文本颜色的自定义UILabel始终变为黑色

Swift 带有渐变文本颜色的自定义UILabel始终变为黑色,swift,text,colors,uilabel,gradient,Swift,Text,Colors,Uilabel,Gradient,我创建了一个自定义UILabel来显示grediant文本,但它总是将文本显示为黑色…当我在视图控制器上使用相同的代码时,它会工作 import UIKit class GradientLabel: UILabel { override func awakeFromNib() { super.awakeFromNib() let gredient = GradientView.init(frame: CGRect(x: 0, y: 0, width:

我创建了一个自定义UILabel来显示grediant文本,但它总是将文本显示为黑色…当我在视图控制器上使用相同的代码时,它会工作

import UIKit

class GradientLabel: UILabel {

    override func awakeFromNib() {
        super.awakeFromNib()
        let gredient = GradientView.init(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
        gredient.bottomColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
        gredient.topColor = #colorLiteral(red: 0.1764705926, green: 0.01176470611, blue: 0.5607843399, alpha: 1)
        setTextColorToGradient(image: imageWithView(view: gredient)!)
    }


    func imageWithView(view: UIView) -> UIImage? {//bet7awel uiview to image
        UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
        view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img
    }

    func setTextColorToGradient(image: UIImage) {//beta7'od image we tekteb beha el text fe el label
        UIGraphicsBeginImageContext(frame.size)
        image.draw(in: bounds)
        let myGradient = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        textColor = UIColor(patternImage: myGradient!)

    }

}

您应该
init
您的标签,而不是
awakeFromNib
因为您的标签没有使用xib

class GradientLabel: UILabel {

    override init(frame: CGRect) {
          super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
    }
}
扩展将非常适合使代码可重用

extension UILabel {
   func setTextColorToGradient(_ image: UIImage) {
      UIGraphicsBeginImageContext(frame.size)
      image.draw(in: bounds)
      let myGradient = UIGraphicsGetImageFromCurrentImageContext()
       UIGraphicsEndImageContext()
      textColor = UIColor(patternImage: myGradient!)
   }
}
用法:

label.setTextColorToGradient(UIImage(named:"someImage")!)

您不想依赖于
awakeFromNib
。此外,您也确实不希望在
init
中执行此操作,因为您希望能够响应大小更改(例如,如果您有约束,并且在首次创建标签后,
框架发生更改)

相反,从
布局子视图
更新渐变,每当视图的
更改时,都会调用该渐变:

@IBDesignable
class GradientLabel: UILabel {

    @IBInspectable var topColor: UIColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1) {
        didSet { setNeedsLayout() }
    }

    @IBInspectable var bottomColor: UIColor = #colorLiteral(red: 0.1764705926, green: 0.01176470611, blue: 0.5607843399, alpha: 1) {
        didSet { setNeedsLayout() }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        updateTextColor()
    }

    private func updateTextColor() {
        let image = UIGraphicsImageRenderer(bounds: bounds).image { _ in
            let gradient = GradientView(frame: bounds)
            gradient.topColor = topColor
            gradient.bottomColor = bottomColor
            gradient.drawHierarchy(in: bounds, afterScreenUpdates: true)
        }

        textColor = UIColor(patternImage: image)
    }

}
这导致:

注意

  • 我使用了新的
    uigraphicsimageender
    ,而不是
    UIGraphicsBeginImageContext
    UIGraphicsGetImageFromCurrentImageContext
    ,以及
    uigraphicsSendImageContext

  • 我没有手动构建
    CGRect
    ,而是使用
    bounds

  • 我已经将它设置为可设计的,这样我就可以在Interface Builder中直接使用它了。我还将颜色设置为可检测的
@IB,这样您就可以在IB中正确调整颜色,而不用去编码了。显然,只有在希望看到IB中渲染的渐变效果时才需要这样做

  • 我已经让它更新梯度(a)时,标签需要再次布局;和(b)当你改变任何一种颜色时


  • 值得一提的是,这是我在本例中使用的
    GradientView

    @IBDesignable
    class GradientView: UIView {
    
        override class var layerClass: AnyClass { return CAGradientLayer.self }
    
        private var gradientLayer: CAGradientLayer { return layer as! CAGradientLayer }
    
        @IBInspectable var topColor: UIColor = .white { didSet { updateColors() } }
        @IBInspectable var bottomColor: UIColor = .blue { didSet { updateColors() } }
    
        override init(frame: CGRect = .zero) {
            super.init(frame: frame)
            updateColors()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            updateColors()
        }
    
        private func updateColors() {
            gradientLayer.colors = [topColor.cgColor, bottomColor.cgColor]
        }
    
    }
    
    在这种情况下,因为我们将
    layerClass
    设置为渐变,所以我们需要做的就是在
    init
    期间对其进行配置,而基本
    layerClass
    将负责响应大小更改


    或者,您可以使用CoreGraphics绘制渐变:

    @IBDesignable
    class GradientLabel: UILabel {
    
        @IBInspectable var topColor: UIColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1) {
            didSet { setNeedsLayout() }
        }
    
        @IBInspectable var bottomColor: UIColor = #colorLiteral(red: 0.1764705926, green: 0.01176470611, blue: 0.5607843399, alpha: 1) {
            didSet { setNeedsLayout() }
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            updateTextColor()
        }
    
        private func updateTextColor() {
            let image = UIGraphicsImageRenderer(bounds: bounds).image { context in
                let colors = [topColor.cgColor, bottomColor.cgColor]
                guard let gradient = CGGradient(colorsSpace: nil, colors: colors as CFArray, locations: nil) else { return }
                context.cgContext.drawLinearGradient(gradient,
                                                     start: CGPoint(x: bounds.midX, y: bounds.minY),
                                                     end: CGPoint(x: bounds.midX, y: bounds.maxY),
                                                     options: [])
            }
    
            textColor = UIColor(patternImage: image)
        }
    
    }
    

    这实现了与第一个示例相同的效果,但可能会有一点效率。

    如果您在代码中创建标签,则不会调用awakeFromNib。此外,您的帧提取得太早。请尝试此库:非常感谢您的帮助和专业澄清……它工作得非常好:)