当梯度重新启动时,如何在swift中使用图像时修复文本上的渐变

时间:2022-03-25 03:53:03

I'm trying to create a gradient on text, I have used UIGraphics to use a gradient image to create this. The problem I'm having is that the gradient is restarting. Does anyone know how I can scale the gradient to stretch to the text?

我正在尝试在文本上创建渐变,我使用UIGraphics来使用渐变图像来创建它。我遇到的问题是渐变正在重新启动。有谁知道如何缩放渐变以拉伸到文本?

The text is on a wireframe and will be altered a couple of times. Sometimes it will be perfect but other times it is not.

文本在线框上,将被更改几次。有时它会很完美,但有时则不是。

The gradient should go yellow to blue but it restarts see photo below:

渐变应该从黄色变为蓝色但重新开始,请参见下面的照片:

当梯度重新启动时,如何在swift中使用图像时修复文本上的渐变

import UIKit

func colourTextWithGrad(label: UILabel) {
    UIGraphicsBeginImageContext(label.frame.size)
    UIImage(named: "testt.png")?.drawInRect(label.bounds)
    let myGradient: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    label.textColor = UIColor(patternImage: myGradient)

}

1 个解决方案

#1


8  

You'll have to redraw the image each time the label size changes

This is because a pattered UIColor is only ever tiled. From the documentation:

这是因为模仿的UIColor只是平铺。从文档:

During drawing, the image in the pattern color is tiled as necessary to cover the given area.

在绘制期间,图案颜色中的图像根据需要平铺以覆盖给定区域。

Therefore, you'll need to change the image size yourself when the bounds of the label changes – as pattern images don't support stretching. To do this, you can subclass UILabel, and override the layoutSubviews method. Something like this should achieve the desired result:

因此,当标签的边界发生变化时,您需要自己更改图像大小 - 因为图案图像不支持拉伸。为此,您可以继承UILabel,并覆盖layoutSubviews方法。这样的事情应该达到预期的效果:

class GradientLabel: UILabel {

    let gradientImage = UIImage(named:"gradient.png")

    override func layoutSubviews() {

        guard let grad = gradientImage else { // skip re-drawing gradient if it doesn't exist
            return
        }

        // redraw your gradient image
        UIGraphicsBeginImageContext(frame.size)
        grad.drawInRect(bounds)
        let myGradient = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        // update text color
        textColor = UIColor(patternImage: myGradient)
    }
}

Although it's worth noting that I'd always prefer to draw a gradient myself – as you can have much more flexibility (say you want to add another color later). Also the quality of your image might be degraded when you redraw it at different sizes (although due to the nature of gradients, this should be fairly minimal).

虽然值得注意的是我总是喜欢自己画一个渐变 - 因为你可以有更大的灵活性(比如说你想稍后添加另一种颜色)。当您以不同的尺寸重绘图像时,图像的质量可能会降低(尽管由于渐变的性质,这应该是相当小的)。

You can draw your own gradient fairly simply by overriding the drawRect of your UILabel subclass. For example:

您可以通过覆盖UILabel子类的drawRect来简单地绘制自己的渐变。例如:

override func drawRect(rect: CGRect) {

    // begin new image context to let the superclass draw the text in (so we can use it as a mask)
    UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
    do {
        // get your image context
        let ctx = UIGraphicsGetCurrentContext()

        // flip context
        CGContextScaleCTM(ctx, 1, -1)
        CGContextTranslateCTM(ctx, 0, -bounds.size.height)

        // get the superclass to draw text
        super.drawRect(rect)
    }

    // get image and end context
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // get drawRect context
    let ctx = UIGraphicsGetCurrentContext()

    // clip context to image
    CGContextClipToMask(ctx, bounds, img.CGImage)

    // define your colors and locations
    let colors = [UIColor.orangeColor().CGColor, UIColor.redColor().CGColor, UIColor.purpleColor().CGColor, UIColor.blueColor().CGColor]
    let locs:[CGFloat] = [0.0, 0.3, 0.6, 1.0]

    // create your gradient
    let grad = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), colors, locs)

    // draw gradient
    CGContextDrawLinearGradient(ctx, grad, CGPoint(x: 0, y:bounds.size.height*0.5), CGPoint(x:bounds.size.width, y:bounds.size.height*0.5), CGGradientDrawingOptions(rawValue: 0))

}

Output:

当梯度重新启动时,如何在swift中使用图像时修复文本上的渐变


Swift 4 & as subclass

class GradientLabel: UILabel {

    // MARK: - Colors to create gradient from
    @IBInspectable open var gradientFrom: UIColor?
    @IBInspectable open var gradientTo: UIColor?

    override func draw(_ rect: CGRect) {
        // begin new image context to let the superclass draw the text in (so we can use it as a mask)
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
        do {
            // get your image context
            guard let ctx = UIGraphicsGetCurrentContext() else { super.draw(rect); return }
            // flip context
            ctx.scaleBy(x: 1, y: -1)
            ctx.translateBy(x: 0, y: -bounds.size.height)
            // get the superclass to draw text
            super.draw(rect)
        }
        // get image and end context
        guard let img = UIGraphicsGetImageFromCurrentImageContext(), img.cgImage != nil else { return }
        UIGraphicsEndImageContext()
        // get drawRect context
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        // clip context to image
        ctx.clip(to: bounds, mask: img.cgImage!)
        // define your colors and locations
        let colors: [CGColor] = [UIColor.orange.cgColor, UIColor.red.cgColor, UIColor.purple.cgColor, UIColor.blue.cgColor]
        let locs: [CGFloat] = [0.0, 0.3, 0.6, 1.0]
        // create your gradient
        guard let grad = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: locs) else { return }
        // draw gradient
        ctx.drawLinearGradient(grad, start: CGPoint(x: 0, y: bounds.size.height*0.5), end: CGPoint(x:bounds.size.width, y: bounds.size.height*0.5), options: CGGradientDrawingOptions(rawValue: 0))
    }
}

#1


8  

You'll have to redraw the image each time the label size changes

This is because a pattered UIColor is only ever tiled. From the documentation:

这是因为模仿的UIColor只是平铺。从文档:

During drawing, the image in the pattern color is tiled as necessary to cover the given area.

在绘制期间,图案颜色中的图像根据需要平铺以覆盖给定区域。

Therefore, you'll need to change the image size yourself when the bounds of the label changes – as pattern images don't support stretching. To do this, you can subclass UILabel, and override the layoutSubviews method. Something like this should achieve the desired result:

因此,当标签的边界发生变化时,您需要自己更改图像大小 - 因为图案图像不支持拉伸。为此,您可以继承UILabel,并覆盖layoutSubviews方法。这样的事情应该达到预期的效果:

class GradientLabel: UILabel {

    let gradientImage = UIImage(named:"gradient.png")

    override func layoutSubviews() {

        guard let grad = gradientImage else { // skip re-drawing gradient if it doesn't exist
            return
        }

        // redraw your gradient image
        UIGraphicsBeginImageContext(frame.size)
        grad.drawInRect(bounds)
        let myGradient = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        // update text color
        textColor = UIColor(patternImage: myGradient)
    }
}

Although it's worth noting that I'd always prefer to draw a gradient myself – as you can have much more flexibility (say you want to add another color later). Also the quality of your image might be degraded when you redraw it at different sizes (although due to the nature of gradients, this should be fairly minimal).

虽然值得注意的是我总是喜欢自己画一个渐变 - 因为你可以有更大的灵活性(比如说你想稍后添加另一种颜色)。当您以不同的尺寸重绘图像时,图像的质量可能会降低(尽管由于渐变的性质,这应该是相当小的)。

You can draw your own gradient fairly simply by overriding the drawRect of your UILabel subclass. For example:

您可以通过覆盖UILabel子类的drawRect来简单地绘制自己的渐变。例如:

override func drawRect(rect: CGRect) {

    // begin new image context to let the superclass draw the text in (so we can use it as a mask)
    UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
    do {
        // get your image context
        let ctx = UIGraphicsGetCurrentContext()

        // flip context
        CGContextScaleCTM(ctx, 1, -1)
        CGContextTranslateCTM(ctx, 0, -bounds.size.height)

        // get the superclass to draw text
        super.drawRect(rect)
    }

    // get image and end context
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // get drawRect context
    let ctx = UIGraphicsGetCurrentContext()

    // clip context to image
    CGContextClipToMask(ctx, bounds, img.CGImage)

    // define your colors and locations
    let colors = [UIColor.orangeColor().CGColor, UIColor.redColor().CGColor, UIColor.purpleColor().CGColor, UIColor.blueColor().CGColor]
    let locs:[CGFloat] = [0.0, 0.3, 0.6, 1.0]

    // create your gradient
    let grad = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), colors, locs)

    // draw gradient
    CGContextDrawLinearGradient(ctx, grad, CGPoint(x: 0, y:bounds.size.height*0.5), CGPoint(x:bounds.size.width, y:bounds.size.height*0.5), CGGradientDrawingOptions(rawValue: 0))

}

Output:

当梯度重新启动时,如何在swift中使用图像时修复文本上的渐变


Swift 4 & as subclass

class GradientLabel: UILabel {

    // MARK: - Colors to create gradient from
    @IBInspectable open var gradientFrom: UIColor?
    @IBInspectable open var gradientTo: UIColor?

    override func draw(_ rect: CGRect) {
        // begin new image context to let the superclass draw the text in (so we can use it as a mask)
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
        do {
            // get your image context
            guard let ctx = UIGraphicsGetCurrentContext() else { super.draw(rect); return }
            // flip context
            ctx.scaleBy(x: 1, y: -1)
            ctx.translateBy(x: 0, y: -bounds.size.height)
            // get the superclass to draw text
            super.draw(rect)
        }
        // get image and end context
        guard let img = UIGraphicsGetImageFromCurrentImageContext(), img.cgImage != nil else { return }
        UIGraphicsEndImageContext()
        // get drawRect context
        guard let ctx = UIGraphicsGetCurrentContext() else { return }
        // clip context to image
        ctx.clip(to: bounds, mask: img.cgImage!)
        // define your colors and locations
        let colors: [CGColor] = [UIColor.orange.cgColor, UIColor.red.cgColor, UIColor.purple.cgColor, UIColor.blue.cgColor]
        let locs: [CGFloat] = [0.0, 0.3, 0.6, 1.0]
        // create your gradient
        guard let grad = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: locs) else { return }
        // draw gradient
        ctx.drawLinearGradient(grad, start: CGPoint(x: 0, y: bounds.size.height*0.5), end: CGPoint(x:bounds.size.width, y: bounds.size.height*0.5), options: CGGradientDrawingOptions(rawValue: 0))
    }
}