如何添加一个渐变到一个UILabel的文本,但不是背景?(How do I add a gradie

2019-06-18 09:22发布

哎,我希望能有在一个UILabel的文本渐变填充我知道CGGradient,但我不知道我应该怎样使用它的一个UILabel的文本

我发现这对谷歌,但我不能设法得到它的工作

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

Answer 1:

(跳至底部全类源代码)

双方布拉德·拉尔森和巴赫真正有用的答案。 第二个为我工作,但它需要的图像存在于提前。 我想要的东西更动态的,所以我这两个解决方案合并为一个:

  • 绘制所需梯度上一个UIImage
  • 使用的UIImage设置颜色图案

结果工作和在下面的截图中可以看到一些希腊字符渲染也没关系。 (I还添加了一个行程,并在梯度顶部的阴影)

下面是与呈现上一个UIImage一个梯度(来实现该功能,我从一个博客帖子得到了我现在找不到引用它的代码的一部分)的方法以及我的标签的定制init方法:

- (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;
}

我会尽力完成该子类的UILabel,并张贴。

编辑

该类完成,这是对我的GitHub仓库 。 阅读关于它在这里 !



Answer 2:

我一直在寻找一个解决方案,DotSlashSlash具有隐藏在评论一个答案!

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

UIImage *myGradient = [UIImage imageNamed:@"textGradient.png"];
myLabel.textColor   = [UIColor colorWithPatternImage:myGradient];


Answer 3:

您提供的例子依赖于你没有访问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);

这种方法的一个缺点是,我使用的核芯显卡功能不能正确处理Unicode文本。

什么代码所做的就是翻转绘图上下文垂直显示(iPhone反转正常的石英坐标系统上为Y轴),设置文本绘制模式相交与剪切路径所绘制的文本,剪辑区域绘制的文本,然后绘制的渐变。 渐变将只能填补文字,而不是背景。

我试图使用的NSString的-drawAtPoint:方法用于此目的,不支持Unicode,但所有的角色跑彼此的顶部,当我切换文本模式kCGTextClip。



Answer 4:

SWIFT 3+

该解决方案@季米特里斯的答案基础上的。 它是在一个扩展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
    }

}

与用法:

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
}


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;
}

道具@Dimitris



Answer 5:

下面是我在斯威夫特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
}


Answer 6:

雨燕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)
    }
}

用法:

label.gradientColors = [UIColor.blue.cgColor, UIColor.red.cgColor]


Answer 7:

你可以子类进行UILable,做自己draw方法。 这可能会是比较困难的做法,有可能是一个更简单的方法。



Answer 8:

最简单的斯威夫特3解决方案

将图像添加到您的项目资产或编程方式创建一个然后执行以下操作:

let image = UIImage(named: "myGradient.png")!
label.textColor = UIColor.init(patternImage: image)


文章来源: How do I add a gradient to the text of a UILabel, but not the background?