【问题标题】:Custom UILabel with gradient text colour always become black具有渐变文本颜色的自定义 UILabel 始终变为黑色
【发布时间】:2019-09-19 06:31:16
【问题描述】:

我创建了一个自定义 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!)

    }

}

【问题讨论】:

  • 如果您在代码中创建标签,则永远不会调用 awakeFromNib。
  • 另外你的帧被提取得太早了。

标签: swift text colors uilabel gradient


【解决方案1】:

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

相反,从layoutSubviews 更新您的渐变,每当视图的frame 更改时都会调用它:

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

}

结果:

注意,

  • 我使用的是新的UIGraphicsImageRenderer,而不是UIGraphicsBeginImageContextUIGraphicsGetImageFromCurrentImageContextUIGraphicsEndImageContext

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

  • 我已将其设为 @IBDesignable,以便我可以直接在 Interface Builder 中使用它。我还制作了颜色@IBInspectable,因此您可以直接在 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)
    }

}

这实现了与第一个示例相同的效果,但可能更高效。

【讨论】:

  • 非常感谢您的帮助和专业的澄清......它工作得很好:)
【解决方案2】:

你应该 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")!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-21
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    • 2016-10-10
    相关资源
    最近更新 更多