聊聊 iOS 实现渐变色文本以及可能你不知道的细节

iOS开发

共 3977字,需浏览 8分钟

 · 2022-01-22

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇

前言

前段时间工作中,产品给了一个实现渐变色文本,并且是放到富文本里面的需求。插入到富文本这里先不说,无非就是生成这个渐变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 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!

点击👆卡片,关注后回复【面试题】即可获取

在看点这里好文分享给更多人↓↓

浏览 41
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报