やりたいこと
UILabelで文字を横にグラデーションさせたい。(文字毎にグラデーションさせる場合は背景設定すれば良いだけになる。後述)
グラデのかかったUIViewを作成し、UILabelをUIImageViewに変換して、マスク処理をかけてやるとこれが作成できる。
コード
func ここから() -> UIImageView {
let label: UILabel = makeLabel(text: "ABCDEFG")
let imageReference: CGImage = makeGradientCGImage(frame: label.bounds)
let maskReference: CGImage = convertImage(label).cgImage!
return makeMaskedImage(imageReference: imageReference, maskReference: maskReference)
}
private func convertImage(_ view: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(view.frame.size, false, UIScreen.main.scale)
let context:CGContext = UIGraphicsGetCurrentContext()!
context.translateBy(x: -view.frame.origin.x, y: -view.frame.origin.y)
view.layer.render(in: context)
let renderedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return renderedImage
}
private func makeLabel(text: String) -> UILabel {
let label = UILabel()
label.font = UIFont.systemFont(20)
label.textColor = UIColor.black
label.backgroundColor = UIColor.white
label.text = text
label.sizeToFit()
return label
}
private func makeGradientCGImage(frame: CGRect) -> CGImage {
let gradientView = UIView(frame: frame)
let layer: CAGradientLayer = CAGradientLayer()
layer.frame = gradientView.bounds
layer.startPoint = CGPoint(x: 0, y: 0.5)
layer.endPoint = CGPoint(x: 1.0, y: 0.5)
layer.colors = [UIColor.colorWithHex(0xFFD195).cgColor, UIColor.colorWithHex(0xF5670C).cgColor]
gradientView.layer.addSublayer(layer)
return gradientView.convertImage(false).cgImage!
}
private func makeMaskedImage(imageReference: CGImage, maskReference: CGImage) -> UIImageView {
let imageMask = CGImage(maskWidth: maskReference.width,
height: maskReference.height,
bitsPerComponent: maskReference.bitsPerComponent,
bitsPerPixel: maskReference.bitsPerPixel,
bytesPerRow: maskReference.bytesPerRow,
provider: maskReference.dataProvider!,
decode: nil,
shouldInterpolate: true)!
let maskedReference: CGImage = imageReference.masking(imageMask)!
return UIImageView(image: UIImage(cgImage: maskedReference))
}
補足
文字毎にグラデーションさせたい場合は、1pxの画像を用意するのがシンプルで良い解決方法のようである。
https://stackoverflow.com/a/4558480