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:
渐变应该从黄色变为蓝色但重新开始,请参见下面的照片:
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 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 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))
}
}