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

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

作者: JerryFans | 来源:发表于2022-01-09 15:49 被阅读0次

    前言

    前段时间工作中,产品给了一个实现渐变色文本,并且是放到富文本里面的需求。插入到富文本这里先不说,无非就是生成这个渐变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)
        }
    

    来看看实现效果:

    image

    看到这里大家是否意味已经大结局了?实际上我一开始确实用此方法直接提交给测试了,结果就翻车了。测试提交了一个如下的Bugs,如果显示了emoj表情,会显示上有bugs如下。

    image

    为什么会有此问题?原理上其实也很简单,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;
    }
    

    接下来就是见证奇迹的时候:

    image

    Demo地址:

    https://github.com/JerryFans/GradientLabelDemo

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/oewmcrtx.html