聊聊 iOS 实现渐变色文本以及可能你不知道的细节
前言
前段时间工作中,产品给了一个实现渐变色文本,并且是放到富文本里面的需求。插入到富文本这里先不说,无非就是生成这个渐变Label的一张Image插入到富文本。
相信大家第一时间可能会去度娘寻求答案,并且马上就能搜索出答案。这里我们来聊聊几种方案的实现,以及产生的问题。
方案一
基于CAGradientLayer做一个mask,核心代码大概如下。
override func layoutSubviews() {
super.layoutSubviews()
guard let config = self.config else { return }
if self.gradientLayer != nil {
return
}
let gradientLayer = CAGradientLayer()
self.gradientLayer = gradientLayer
gradientLayer.colors = [config.startColor.cgColor,config.endColor.cgColor]
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)
gradientLayer.frame = self.label.frame
gradientLayer.mask = self.label.layer
self.label.layer.frame = gradientLayer.bounds
self.layer.insertSublayer(gradientLayer, at: 0)
}
来看看实现效果:
看到这里大家是否意味已经大结局了?实际上我一开始确实用此方法直接提交给测试了,结果就翻车了。测试提交了一个如下的Bugs,如果显示了emoj表情,会显示上有bugs如下。
为什么会有此问题?原理上其实也很简单,CAGradientLayer的方式,实际上是在Label上面盖一层蒙版,如果用了emoj系统可不会给你考虑那么多,翻车倒是正常。所以接下来就要考虑另外一种方式了。
方案二
基于UIColor(patternImage: gradientImage),这个方法,直接给Label设置一张渐变的图片的颜色。(注意这个gradientImage要与你Label的Frame大小是要一致的,不然那个渐变效果不一定会和设计一致。)代码大概如下:
@objc convenience init(config: GradientPatternLabelConfig) {
self.init(frame: .zero)
self.config = config
self.label.font = config.font
self.label.text = config.text
self.addSubview(self.label)
self.label.sizeToFit()
self.label.lineBreakMode = config.lineBreakMode
let size = (config.maxWidth == 0 || self.label.jf.size.width < config.maxWidth) ? self.label.jf.size : CGSize(width: config.maxWidth, height: self.label.jf.size.height)
if config.startColor == UIColor.clear {
self.label.textColor = config.textColor
}
else if let gradientImage = ConvertGradientImage.gradientImage(with: config, size: size) {
self.label.textColor = UIColor(patternImage: gradientImage)
}
else {
self.label.textColor = config.startColor
}
let frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
self.label.frame = frame
self.frame = frame
}
生成gradientImage的代码:
+ (UIImage *_Nullable)gradientImageWithConfig:(GradientPatternLabelConfig *_Nonnull)config size:(CGSize)size {
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
//绘制渐变层
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradientRef = CGGradientCreateWithColors(colorSpaceRef,
(__bridge CFArrayRef)@[(id)config.startColor.CGColor,(id)config.endColor.CGColor],
NULL);
CGPoint startPoint = CGPointZero;
CGRect rect = CGRectMake(0, 0, size.width, size.height);
CGPoint endPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGContextDrawLinearGradient(context, gradientRef, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
//取到渐变图片
UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();
//释放资源
CGColorSpaceRelease(colorSpaceRef);
CGGradientRelease(gradientRef);
UIGraphicsEndImageContext();
return gradientImage;
}
接下来就是见证奇迹的时候:
Demo地址:
https://github.com/JerryFans/GradientLabelDemo
作者:jerryfans
https://juejin.cn/post/7048277162415095844
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
面试题
】即可获取评论