如何在UILabel的文本中添加渐变,而不是背景?

Dot*_*ash 26 iphone gradient core-graphics objective-c uilabel

嘿,我希望能够在UILabel中对文本进行渐变填充我知道CGGradient但是我不知道如何在UILabel的文本上使用它

我在谷歌上找到了这个,但我无法让它运作起来

http://silverity.livejournal.com/26436.html

Bac*_*ach 112

我正在寻找一个解决方案,DotSlashSlash的答案隐藏在其中一条评论中!

为了完整起见,答案和最简单的解决方案是:

UIImage *myGradient = [UIImage imageNamed:@"textGradient.png"];
myLabel.textColor   = [UIColor colorWithPatternImage:myGradient];
Run Code Online (Sandbox Code Playgroud)

  • 太棒了 (3认同)

Dim*_*ris 40

(跳到底部获取完整的类源代码)

Brad Larson和Bach都非常有用的答案.第二个对我有用,但它要求提前出现图像.我想要更有活力的东西,所以我把两个解决方案合二为一:

  • 在UIImage上绘制所需的渐变
  • 使用UIImage设置颜色模式

结果有效,在下面的屏幕截图中,您可以看到一些希腊字符也很好.(我还在渐变顶部添加了笔触和阴影)

iOS风格化UILabel,大棕色狐狸

这是我的标签的自定义init方法以及在UIImage上呈现渐变的方法(我从博客文章获得的该功能的代码的一部分,我现在找不到它来引用它):

- (id)initWithFrame:(CGRect)frame text:(NSString *)aText {
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.text = aText;

        self.textColor = [UIColor colorWithPatternImage:[self gradientImage]];

    }
    return self;
}

- (UIImage *)gradientImage
{
    CGSize textSize = [self.text sizeWithFont:self.font];
    CGFloat width = textSize.width;         // max 1024 due to Core Graphics limitations
    CGFloat height = textSize.height;       // max 1024 due to Core Graphics limitations

    // create a new bitmap image context
    UIGraphicsBeginImageContext(CGSizeMake(width, height));

    // get context
    CGContextRef context = UIGraphicsGetCurrentContext();       

    // push context to make it current (need to do this manually because we are not drawing in a UIView)
    UIGraphicsPushContext(context);                             

    //draw gradient    
    CGGradientRef glossGradient;
    CGColorSpaceRef rgbColorspace;
    size_t num_locations = 2;
    CGFloat locations[2] = { 0.0, 1.0 };
    CGFloat components[8] = { 0.0, 1.0, 1.0, 1.0,  // Start color
                            1.0, 1.0, 0.0, 1.0 }; // End color
    rgbColorspace = CGColorSpaceCreateDeviceRGB();
    glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
    CGPoint topCenter = CGPointMake(0, 0);
    CGPoint bottomCenter = CGPointMake(0, textSize.height);
    CGContextDrawLinearGradient(context, glossGradient, topCenter, bottomCenter, 0);

    CGGradientRelease(glossGradient);
    CGColorSpaceRelease(rgbColorspace); 

    // pop context 
    UIGraphicsPopContext();                             

    // get a UIImage from the image context
    UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();

    // clean up drawing environment
    UIGraphicsEndImageContext();

    return  gradientImage;
}
Run Code Online (Sandbox Code Playgroud)

我将尝试完成该UILabel子类并发布它.

编辑:

该类已完成,它位于我的GitHub存储库中.在这里阅读它!


Le *_*inh 17

斯威夫特 4.1

class GradientLabel: UILabel {
    var gradientColors: [CGColor] = []

    override func drawText(in rect: CGRect) {
        if let gradientColor = drawGradientColor(in: rect, colors: gradientColors) {
            self.textColor = gradientColor
        }
        super.drawText(in: rect)
    }

    private func drawGradientColor(in rect: CGRect, colors: [CGColor]) -> UIColor? {
        let currentContext = UIGraphicsGetCurrentContext()
        currentContext?.saveGState()
        defer { currentContext?.restoreGState() }

        let size = rect.size
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(),
                                        colors: colors as CFArray,
                                        locations: nil) else { return nil }

        let context = UIGraphicsGetCurrentContext()
        context?.drawLinearGradient(gradient,
                                    start: CGPoint.zero,
                                    end: CGPoint(x: size.width, y: 0),
                                    options: [])
        let gradientImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        guard let image = gradientImage else { return nil }
        return UIColor(patternImage: image)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

label.gradientColors = [UIColor.blue.cgColor, UIColor.red.cgColor]
Run Code Online (Sandbox Code Playgroud)

  • 非常适合水平渐变 (2认同)

Bra*_*son 14

您提供的示例依赖于您无法在iPhone上访问的私有文本绘图功能. 作者在后续文章中提供了如何使用公共API执行此操作的示例.他后来的例子使用渐变图像作为文本的颜色.(不幸的是,似乎他的博客已被删除,但请参阅巴赫在这里使用的方法的答案.)

如果您仍想在代码中为文本颜色绘制渐变,可以通过继承UILabel并覆盖-drawRect:来完成以下代码:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0f, self.bounds.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);

CGContextSelectFont(context, "Helvetica", 20.0f, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextClip);
CGContextSetTextPosition(context, 0.0f, round(20.0f / 4.0f));
CGContextShowText(context, [self.text UTF8String], strlen([self.text UTF8String]));

CGContextClip(context);

CGGradientRef gradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 1.0,  // Start color
    1.0, 1.0, 1.0, 0.1 }; // End color

rgbColorspace = CGColorSpaceCreateDeviceRGB();
gradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGRect currentBounds = self.bounds;
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawLinearGradient(context, gradient, topCenter, midCenter, 0);

CGGradientRelease(gradient);
CGColorSpaceRelease(rgbColorspace);         

CGContextRestoreGState(context);
Run Code Online (Sandbox Code Playgroud)

这种方法的一个缺点是我使用的核心图形函数不能正确处理Unicode文本.

代码的作用是垂直翻转绘图上下文(iPhone反转Y轴上的普通Quartz坐标系),设置文本绘制模式以使绘制文本与剪切路径相交,剪切区域以绘制到文本,然后绘制渐变.渐变仅填充文本,而不是背景.

我尝试使用NSString的-drawAtPoint:方法,它支持Unicode,但是当我将文本模式切换到kCGTextClip时,所有字符都在另一个上面运行.

  • 谢谢你:)我刚刚使用了模式图像方法label.textColor = [UIColor colorWithPatternImage:gradientImage; (11认同)

Bra*_*n A 14

SWIFT 3+

这个解决方案基于@Dimitris的答案.它是在一个扩展UILabel类,将在标签的文本创建的梯度为您传递startColorendColor.该UILabel扩展是以下:

extension UILabel {

    func applyGradientWith(startColor: UIColor, endColor: UIColor) -> Bool {

        var startColorRed:CGFloat = 0
        var startColorGreen:CGFloat = 0
        var startColorBlue:CGFloat = 0
        var startAlpha:CGFloat = 0

        if !startColor.getRed(&startColorRed, green: &startColorGreen, blue: &startColorBlue, alpha: &startAlpha) {
            return false
        }

        var endColorRed:CGFloat = 0
        var endColorGreen:CGFloat = 0
        var endColorBlue:CGFloat = 0
        var endAlpha:CGFloat = 0

        if !endColor.getRed(&endColorRed, green: &endColorGreen, blue: &endColorBlue, alpha: &endAlpha) {
            return false
        }

        let gradientText = self.text ?? ""

        let name:String = NSFontAttributeName
        let textSize: CGSize = gradientText.size(attributes: [name:self.font])
        let width:CGFloat = textSize.width
        let height:CGFloat = textSize.height

        UIGraphicsBeginImageContext(CGSize(width: width, height: height))

        guard let context = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return false
        }

        UIGraphicsPushContext(context)

        let glossGradient:CGGradient?
        let rgbColorspace:CGColorSpace?
        let num_locations:size_t = 2
        let locations:[CGFloat] = [ 0.0, 1.0 ]
        let components:[CGFloat] = [startColorRed, startColorGreen, startColorBlue, startAlpha, endColorRed, endColorGreen, endColorBlue, endAlpha]
        rgbColorspace = CGColorSpaceCreateDeviceRGB()
        glossGradient = CGGradient(colorSpace: rgbColorspace!, colorComponents: components, locations: locations, count: num_locations)
        let topCenter = CGPoint.zero
        let bottomCenter = CGPoint(x: 0, y: textSize.height)
        context.drawLinearGradient(glossGradient!, start: topCenter, end: bottomCenter, options: CGGradientDrawingOptions.drawsBeforeStartLocation)

        UIGraphicsPopContext()

        guard let gradientImage = UIGraphicsGetImageFromCurrentImageContext() else {
            UIGraphicsEndImageContext()
            return false
        }

        UIGraphicsEndImageContext()

        self.textColor = UIColor(patternImage: gradientImage)

        return true
    }

}
Run Code Online (Sandbox Code Playgroud)

用法:

let text = "YAAASSSSS!"
label.text = text
if label.applyGradientWith(startColor: .red, endColor: .blue) {
    print("Gradient applied!")
}
else {
    print("Could not apply gradient")
    label.textColor = .black
}
Run Code Online (Sandbox Code Playgroud)

YAAASSSSS!


SWIFT 2

class func getGradientForText(text: NSString) -> UIImage {

    let font:UIFont = UIFont(name: "YourFontName", size: 50.0)!
    let name:String = NSFontAttributeName
    let textSize: CGSize = text.sizeWithAttributes([name:font])
    let width:CGFloat = textSize.width         // max 1024 due to Core Graphics limitations
    let height:CGFloat = textSize.height       // max 1024 due to Core Graphics limitations

    //create a new bitmap image context
    UIGraphicsBeginImageContext(CGSizeMake(width, height))

    // get context
    let context = UIGraphicsGetCurrentContext()

    // push context to make it current (need to do this manually because we are not drawing in a UIView)
    UIGraphicsPushContext(context!)

    //draw gradient
    let glossGradient:CGGradientRef?
    let rgbColorspace:CGColorSpaceRef?
    let num_locations:size_t = 2
    let locations:[CGFloat] = [ 0.0, 1.0 ]
    let components:[CGFloat] = [(202 / 255.0), (197 / 255.0), (52 / 255.0), 1.0,  // Start color
                                (253 / 255.0), (248 / 255.0), (101 / 255.0), 1.0] // End color
    rgbColorspace = CGColorSpaceCreateDeviceRGB();
    glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
    let topCenter = CGPointMake(0, 0);
    let bottomCenter = CGPointMake(0, textSize.height);
    CGContextDrawLinearGradient(context, glossGradient, topCenter, bottomCenter, CGGradientDrawingOptions.DrawsBeforeStartLocation);

    // pop context
    UIGraphicsPopContext();

    // get a UIImage from the image context
    let gradientImage = UIGraphicsGetImageFromCurrentImageContext();

    // clean up drawing environment
    UIGraphicsEndImageContext();

    return  gradientImage;
}
Run Code Online (Sandbox Code Playgroud)

推荐给@Dimitris


小智 7

有一个非常简单的解决方案!以下是向 UILabel 文本添加渐变颜色的方法。

\n\n

我们只需两步即可实现这一目标:

\n\n
    \n
  1. 创建渐变图像
  2. \n
  3. 将渐变图像作为 textColor 应用到 UILabel
  4. \n
\n\n

1.创建渐变图像

\n\n
extension UIImage {\n    static func gradientImageWithBounds(bounds: CGRect, colors: [CGColor]) -> UIImage {\n        let gradientLayer = CAGradientLayer()\n        gradientLayer.frame = bounds\n        gradientLayer.colors = colors\n\n        UIGraphicsBeginImageContext(gradientLayer.bounds.size)\n        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)\n        let image = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        return image!\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

按如下方式使用:

\n\n
let gradientImage = UIImage.gradientImageWithBounds(bounds: myLabel.bounds, colors: [firstColor.cgColor, secondColor.cgColor])\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\xa0\x80

\n\n

2.将渐变图像作为textColor应用到UILabel

\n\n
myLabel.textColor = UIColor.init(patternImage: gradientImage)\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\xa0\x80

\n\n

笔记:

\n\n

如果你希望渐变是水平的,只需将这两行添加到gradientLayer实例中:

\n\n
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)\ngradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\xa0\x80

\n\n

笔记2:

\n\n

UIImage 扩展功能也可以与其他 UIView 一起使用;不仅仅是 UILabel!因此,无论您使用哪个 UIView 应用渐变颜色,都可以随意使用此方法。

\n


Cod*_*ace 5

这是我在 Swift 3 中所做的

override func viewDidLoad() {
    super.viewDidLoad()
    timerLabel.textColor = UIColor(patternImage: gradientImage(size: timerLabel.frame.size, color1: CIColor(color: UIColor.green), color2: CIColor(color: UIColor.red), direction: .Left))
}

func gradientImage(size: CGSize, color1: CIColor, color2: CIColor, direction: GradientDirection = .Up) -> UIImage {

    let context = CIContext(options: nil)
    let filter = CIFilter(name: "CILinearGradient")
    var startVector: CIVector
    var endVector: CIVector

    filter!.setDefaults()

    switch direction {
    case .Up:
        startVector = CIVector(x: size.width * 0.5, y: 0)
        endVector = CIVector(x: size.width * 0.5, y: size.height)
    case .Left:
        startVector = CIVector(x: size.width, y: size.height * 0.5)
        endVector = CIVector(x: 0, y: size.height * 0.5)
    case .UpLeft:
        startVector = CIVector(x: size.width, y: 0)
        endVector = CIVector(x: 0, y: size.height)
    case .UpRight:
        startVector = CIVector(x: 0, y: 0)
        endVector = CIVector(x: size.width, y: size.height)
    }

    filter!.setValue(startVector, forKey: "inputPoint0")
    filter!.setValue(endVector, forKey: "inputPoint1")
    filter!.setValue(color1, forKey: "inputColor0")
    filter!.setValue(color2, forKey: "inputColor1")

    let image = UIImage(cgImage: context.createCGImage(filter!.outputImage!, from: CGRect(x: 0, y: 0, width: size.width, height: size.height))!)
    return image
}
Run Code Online (Sandbox Code Playgroud)