Пользовательский UILabel с градиентным цветом текста всегда становится черным - PullRequest
2 голосов
/ 30 апреля 2019

Я создал пользовательскую 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!)

    }

}

Ответы [ 2 ]

0 голосов
/ 30 апреля 2019

Вы не хотите полагаться на 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)
    }

}

В результате:

example label

Примечание,

  • Я использовал новые UIGraphicsImageRenderer вместо UIGraphicsBeginImageContext, UIGraphicsGetImageFromCurrentImageContext и UIGraphicsEndImageContext.

  • Вместо того, чтобы строить CGRect вручную, я просто использую bounds.

  • Я сделал это @IBDesignable, чтобы я могиспользуйте его непосредственно в Интерфейсном Разработчике.Я также сделал цвета @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)
    }

}

Это достигается так же, как в первом примере, но потенциально немного более эффективно.

0 голосов
/ 30 апреля 2019

Вы должны 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")!)
...