Adding a CGGradient as sublayer to UILabel hides the text of label
Asked Answered
C

7

24

I want to add the gradient as a background to label. I used the following code to acheive that. but the problem is that though the gradient color appears on the label, but the text is not visible. please help

lblPatientDetail.text=PatientsDetails;

lblPatientDetail.textColor=[UIColor blackColor];  

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = lblPatientDetail.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor],(id)[[UIColor colorWithRed:255/255.0 green:239/255.0 blue:215/255.0 alpha:1.0] CGColor],nil];  

[lblPatientDetail.layer addSublayer:gradient];

lblPatientDetail.backgroundColor=[UIColor clearColor];
Circumference answered 31/1, 2011 at 11:7 Comment(0)
G
22

Inserting a sublayer to a UILabel hides the text, so the best way to get what you want is to add the label and gradient layer to a UIView.

UIView *gradientLabelView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = gradientLabelView.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor],(id)[[UIColor colorWithRed:255/255.0 green:239/255.0 blue:215/255.0 alpha:1.0] CGColor],nil];

[gradientLabelView.layer addSublayer:gradient];

lblPatientDetail.frame = gradientLabelView.bounds;
lblPatientDetail.backgroundColor = [UIColor clearColor];
[gradientLabelView addSubview:lblPatientDetail];

[self addSubview:gradientLabelView];
Gordon answered 31/1, 2011 at 11:49 Comment(4)
ya I know that its getting added above text :(... can you tell me how to add this layer at back..I have already tried this line you suggested. It dint work out. I changed the indexes also but to no avail :) please help, thanks in advance :)Circumference
I'm not sure, it might be that you can't do this on UILabels. You could try creating a UIView with a gradient and then add the label as a subview.Gordon
Thanks James I tried your second option :) added the gradient on UIView and than added the label as subview :-)Circumference
change the background color of your modified UILabel to [UIColor clearColor]. If you don't UILabel backgrounds are defaulted to whitebackground :PJarv
J
2

The suggested answer with the UILabel inside a UIView works. Apparently UILabels cannot have text within them after giving the background a gradient color background... don't know why....

But heres the full code for the solution.... hope this helps someone :)

UIView *EnvironmentalsLabelView = [[UIView alloc] initWithFrame:CGRectMake(0, 300, 320, 20)];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = EnvironmentalsLabelView.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor]CGColor], (id)[[UIColor blackColor]CGColor], nil];
[EnvironmentalsLabelView.layer insertSublayer:gradient atIndex:0];
[scroller addSubview:EnvironmentalsLabelView];

UILabel *EnviornmentalsLabelText = [[UILabel alloc] initWithFrame:EnvironmentalsLabelView.bounds];
[EnviornmentalsLabelText setFont:[UIFont fontWithName:@"Arial-BoldMT" size:12.0f]];
EnviornmentalsLabelText.textAlignment = NSTextAlignmentCenter;
EnviornmentalsLabelText.backgroundColor = [UIColor clearColor];
EnviornmentalsLabelText.text = @"Environmental Benefits";
[EnvironmentalsLabelView addSubview:EnviornmentalsLabelText];

Happy coding!!!!

Jarv answered 17/6, 2013 at 23:50 Comment(1)
Can we do the same without using extra viewsInsignificance
P
1

One more additional think to correct answer. If you are use autolayouts for place your custom view you can get this problem - http://prntscr.com/5tj7bx

So your view has a different size then subView - UILabel and subLayer - gradient layer.

I solve this problem by add one method

class wResultView: UIView {
var label = UILabel()
var gradientLayer = CAGradientLayer()

override func layoutSubviews() {
    gradientLayer.frame = self.bounds
    label.frame = self.bounds
}
......
Phraseogram answered 17/1, 2015 at 13:53 Comment(0)
J
0

Simplest solution.

It's a huge mistake by Apple, they have never fixed for 20? years.

To work around, simply add another UILabel on top and pass on the ".text" setting.

class TrickLabel: UIILabel {
    override var text: String? {
        didSet {
            _label.text = text
        }
    }
    private lazy var bg: CAGradientLayer = {
        let l = CAGradientLayer()
        l.startPoint = CGPoint(x: 0.5, y: 0)
        l.endPoint = CGPoint(x: 0.5, y: 1)
        l.locations = [-1, 2]
        l.colors = [UIColor.cyan,UIColor.yellow].compactMap{$0.cgColor}
        layer.insertSublayer(l, at: 0) // NOTE, MUST USE INSERT NOT ADD
        return l
    }()
    private lazy var _label: UILabel = {
        let v = UILabel.Typical
        v.backgroundColor = .clear
        v.font = blah
        addSubview(v)
        v.bindEdgesToSuperview()
        return v
    }()
    override func layoutSubviews() {
        super.layoutSubviews()
        bg.frame = bounds
        _ = _label
    }
}

If necessary, you can also "pass along" eg the font, text color etc.

It's that easy. TrickLabel works exactly like a UILabel, you can say .text = "blah" etc as normal.

Jellyfish answered 21/5 at 12:24 Comment(0)
B
-1

The solution which implies creation of UIView is not very convenient for regular use. Let me suggest a reusable solution for this.

import UIKit

@IBDesignable
class GradientTextLabel: UILabel {
    // MARK: - Public vars
    @IBInspectable var startColor: UIColor = .red { didSet { setNeedsDisplay() } }
    @IBInspectable var midColor: UIColor = .orange { didSet { setNeedsDisplay() } }
    @IBInspectable var endColor: UIColor = .yellow { didSet { setNeedsDisplay() } }
    @IBInspectable var vertical = false { didSet { setNeedsDisplay() } }
    
    // MARK: - Lifecycle methods
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let gradient = getGradientLayer(bounds: bounds)
        textColor = gradientColor(bounds: bounds, gradientLayer: gradient)
    }
    
    override func prepareForInterfaceBuilder() {
        setNeedsDisplay()
    }
    
    // MARK: - Private methods
    private func getGradientLayer(bounds : CGRect) -> CAGradientLayer{
        let gradient = CAGradientLayer()
        gradient.frame = bounds
        gradient.colors = [startColor.cgColor, midColor.cgColor, endColor.cgColor]
        
        if vertical {
            gradient.startPoint = CGPoint(x: 0.5, y: 0.0)
            gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
        } else {
            gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
        }
        
        return gradient
    }
    
    private func gradientColor(bounds: CGRect, gradientLayer :CAGradientLayer) -> UIColor? {
        UIGraphicsBeginImageContext(gradientLayer.bounds.size)
        //create UIImage by rendering gradient layer.
        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        //get gradient UIcolor from gradient UIImage
        return UIColor(patternImage: image!)
    }
}
Belt answered 10/12, 2021 at 12:12 Comment(0)
F
-2

You can add UILabel within UILabel Like this.

class GradientLabel: UILabel {  

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.clipsToBounds = true
        DispatchQueue.main.async {
            self.applyGradient(with: Color.gradientColor, gradient: GradientOrientation.topLeftBottomRight)
            self.textColor = UIColor.white
        }
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {

            let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
            label.text = self.text
            label.font = self.font
            label.textColor = self.textColor
            label.textAlignment = self.textAlignment
            self.text = ""
            self.addSubview(label)
        }
    }
}

extension UIView {

    func applyGradient(with colours: [UIColor], locations: [NSNumber]? = nil) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = colours.map { $0.cgColor }
        gradient.locations = locations
        self.layer.insertSublayer(gradient, at: 0)
    }

    func applyGradient(with colours: [UIColor], gradient orientation: GradientOrientation) {
        let gradient = CAGradientLayer()
        gradient.frame = self.bounds
        gradient.colors = colours.map { $0.cgColor }
        gradient.startPoint = orientation.startPoint
        gradient.endPoint = orientation.endPoint
        self.layer.insertSublayer(gradient, at: 0)
    }
}
Fallal answered 28/3, 2020 at 13:50 Comment(0)
D
-4

I think you can create a gradient color by adjusting the alpha value in the above code.

gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor],(id)[[UIColor colorWithRed:255/255.0 green:239/255.0 blue:215/255.0 alpha:0.1] CGColor],nil];

I was able to get a gradient effect by doing so.

Damiondamita answered 11/1, 2012 at 12:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.