iOS-UILabel文字渐变颜色扫描

闲暇无事,整点骚操作。

想了半天,来个文字扫描,整点儿花的
先来一个效果图


渐变色扫描.gif

直接开整

干活

Objective-C、Swift实现思路是一样的,就语言区别,文章最后附代码
先想想效果,一道斜杠的渐变颜色区间,匀速往右边扫描过去,然后再回来。
然后开始想象思路。

首先

言语表达不出来,我淦!总之就是需要一块渐变背景左右晃来晃去~
直接上代码

第一步

创建一个UILabel的子类,重写drawRect

1、正常的重绘
- (void)drawRect:(CGRect)rect {
    /*
    coding
    */
    //获取上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //复制文本的对其格式和字体
    NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
    style.alignment = self.textAlignment;
    NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
    [attributes setValue:style forKey:NSParagraphStyleAttributeName];
    [attributes setValue:self.font forKey:NSFontAttributeName];
    [self.text drawWithRect:rect options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];
    //重设mask
    CGContextTranslateCTM(context, 0.0f, rect.size.height);
    CGContextScaleCTM(context, 1.0f, -1.0f);
    CGImageRef alphaMsk = NULL;
    alphaMsk = CGBitmapContextCreateImage(context);
    CGContextClearRect(context, rect);
    CGContextClipToMask(context, rect, alphaMsk);
     /*
    coding
    */
}
2、创建渐变的背景

既然要左右晃动,那就默认把这个渐变背景的长度设置为label长度的三倍,最左边和最右边为字体原有颜色,中间为渐变色,当这个渐变背景左右滑动时,也就实现了渐变背景的扫描效果。

- (void)drawRect:(CGRect)rect {
    //每次刷新的增量,设置成静态变量防止每次都被初始化
    static CGFloat adding = 0;
    //往左还是往右,YES为有,NO为左
    static BOOL add = YES;
    /*
     coding
    */
    //创建一个渐变色颜色空间
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)self.colors, NULL);
    
    //设置渐变色的起点坐标和终点坐标
    CGPoint startPoint = CGPointMake(-rect.size.width, 0);
    CGPoint endPoint = CGPointMake(0, rect.size.height);
    if (adding >= rect.size.width * 2) {
        add = NO;
    }else if (adding <= 0) {
        add = YES;
    }
    //增量设置为字体宽度的150分之1
    if (add) {
        adding += rect.size.width /150;
    }else{
        adding -= rect.size.width /150;
    }
    startPoint = CGPointMake(startPoint.x +adding, startPoint.y);
    endPoint = CGPointMake(endPoint.x +adding, endPoint.y);
    //绘制渐变层
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
    CGColorSpaceRelease(colorSpace);
    CGGradientRelease(gradient);
    CFRelease(alphaMsk);
}
3、创建每帧调用CADisplayLink

让每帧都去调用setNeedsDisplay,重新绘制label

/// 开始动画扫描
- (void)startTextGradient {
    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeState)];
    if (@available(iOS 10, *)) {
        //每秒执行的次数,1秒刷新60次
        self.link.preferredFramesPerSecond = 60;
    }else{
        //多少帧刷新1次,1就代表每帧都刷新
        self.link.frameInterval = 1;
    }
    [self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)changeState {
    [self setNeedsDisplay];
}
4、触发条件

创建一个公有属性gradientColor,存储设置的渐变色数组
setter方法里面做判断
如果设置的为空,代表不需要渐变,所以直接移除正在执行的扫描动画
如果有值,那就启动扫描


当没有设置渐变颜色的时候,我们就需要默认颜色为label设置的颜色,因为渐变,所以要设置成两个相同的颜色,让它看起来没有渐变效果。
所以再创建一个colors的数组存储转换为CGColor类型的颜色

- (void)setGradientColor:(NSArray<UIColor *> *)gradientColor {
    _gradientColor = gradientColor;
    if (!gradientColor || gradientColor.count == 0) {
        if (self.link) {
            [self.link removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
        }
    }else{
        [self startTextGradient];
    }
}

- (NSMutableArray *)colors {
    NSMutableArray *tempColors = [[NSMutableArray alloc] init];
    for (UIColor *color in self.gradientColor) {
        [tempColors addObject:(id)color.CGColor];
    }
    if (tempColors.count == 0) {
        [tempColors addObject:(id)self.textColor.CGColor];
        [tempColors addObject:(id)self.textColor.CGColor];
    }
    return tempColors;
}

这样一个文字渐变色扫描就完成了
用法

UIGradientLabel *label = ({
        UIGradientLabel *label = [[UIGradientLabel alloc] initWithFrame:CGRectMake(100, 300, self.view.frame.size.width - 200, 60)];
        label.text = @"文字开始渐变背景颜色扫描";
        label.textAlignment = NSTextAlignmentCenter;
        label.numberOfLines = 0;
        label.font = [UIFont systemFontOfSize:18];
        label.textColor = COLOR_HEX(0x3EFF32);
        label.gradientColor = @[label.textColor, label.textColor, COLOR_HEX(0xFF2E27),COLOR_HEX(0xFC1AFF), label.textColor, label.textColor];
        label;
    });
    [self.view addSubview:label];

demo地址:Swift+OC文字渐变色扫描

代码

Objective-C
UIGradientLabel.h

//
//  UIGradientLabel.h
//  GradientLabel
//
//  Created by xxx on 2022/1/19.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIGradientLabel : UILabel
//渐变的颜色
@property (nonatomic, copy, nullable) NSArray<UIColor *> *gradientColor;

@end

NS_ASSUME_NONNULL_END

UIGradientLabel.m

//
//  UIGradientLabel.m
//  GradientLabel
//
//  Created by xxx on 2022/1/19.
//

#import "UIGradientLabel.h"

@interface UIGradientLabel()
//渐变颜色
@property (nonatomic, strong) NSMutableArray *colors;
//时间帧
@property (nonatomic, strong) CADisplayLink *link;

@end

@implementation UIGradientLabel

/// 开始动画扫描
- (void)startTextGradient {
    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeState)];
    if (@available(iOS 10, *)) {
        //每秒执行的次数,1秒刷新60次
        self.link.preferredFramesPerSecond = 60;
    }else{
        //多少帧刷新1次,1就代表每帧都刷新
        self.link.frameInterval = 1;
    }
    [self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)drawRect:(CGRect)rect {
    static CGFloat adding = 0;
    static BOOL add = YES;
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
    style.alignment = self.textAlignment;
    NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
    [attributes setValue:style forKey:NSParagraphStyleAttributeName];
    [attributes setValue:self.font forKey:NSFontAttributeName];
    [self.text drawWithRect:rect options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];
    
    CGContextTranslateCTM(context, 0.0f, rect.size.height);
    CGContextScaleCTM(context, 1.0f, -1.0f);
    CGImageRef alphaMsk = NULL;
    alphaMsk = CGBitmapContextCreateImage(context);
    CGContextClearRect(context, rect);
    CGContextClipToMask(context, rect, alphaMsk);
    
    //画渐变色
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)self.colors, NULL);
    
    CGPoint startPoint = CGPointMake(-rect.size.width, 0);
    CGPoint endPoint = CGPointMake(0, rect.size.height);
    if (adding >= rect.size.width * 2) {
        add = NO;
    }else if (adding <= 0) {
        add = YES;
    }
    if (add) {
        adding += rect.size.width /150;
    }else{
        adding -= rect.size.width /150;
    }
    startPoint = CGPointMake(startPoint.x +adding, startPoint.y);
    endPoint = CGPointMake(endPoint.x +adding, endPoint.y);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
    CGColorSpaceRelease(colorSpace);
    CGGradientRelease(gradient);
    CFRelease(alphaMsk);
}

- (void)changeState {
    [self setNeedsDisplay];
}

- (void)setGradientColor:(NSArray<UIColor *> *)gradientColor {
    _gradientColor = gradientColor;
    if (!gradientColor || gradientColor.count == 0) {
        if (self.link) {
            [self.link removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
        }
    }else{
        [self startTextGradient];
    }
}

- (NSMutableArray *)colors {
    NSMutableArray *tempColors = [[NSMutableArray alloc] init];
    for (UIColor *color in self.gradientColor) {
        [tempColors addObject:(id)color.CGColor];
    }
    if (tempColors.count == 0) {
        [tempColors addObject:(id)self.textColor.CGColor];
        [tempColors addObject:(id)self.textColor.CGColor];
    }
    return tempColors;
}

@end

Swift
UIGradientLabel.swift

//
//  UIGradientLabel.swift
//  GradientLabel-Swift
//
//  Created by xxx on 2022/1/19.
//

import UIKit

class UIGradientLabel: UILabel {
    private var link : CADisplayLink? = nil
    private var colors : [Any] {
        get {
            guard let gradientColors = gradientColor else{
                return [self.textColor.cgColor,self.textColor.cgColor]
            }
            var color : [Any] = []
            for c in gradientColors {
                color.append(c.cgColor)
            }
            return color
        }
    }
    var gradientColor : [UIColor]?

    func startTextGradient() {
        link = CADisplayLink.init(target: self, selector: #selector(changeState))
        if #available(iOS 10.0, *) {
            link?.preferredFramesPerSecond = 60;
        }else{
            link?.frameInterval = 1
        }
        link?.add(to: RunLoop.current, forMode: .common)
    }
    
    @objc private func changeState() {
        self.setNeedsDisplay()
    }
    
    override func draw(_ rect: CGRect) {
        struct ConsoleBox {
            static var adding : CGFloat = 0
            static var add : Bool = true
        }
        let context = UIGraphicsGetCurrentContext()
        let style : NSMutableParagraphStyle = NSMutableParagraphStyle.init()
        style.alignment = self.textAlignment
        var attribute : [NSAttributedString.Key : Any]? = [:]
        attribute?.updateValue(style, forKey: .paragraphStyle)
        attribute?.updateValue(self.font as Any, forKey:.font)
        self.text?.draw(with: rect, options: .usesLineFragmentOrigin, attributes: attribute, context: nil)
        context?.translateBy(x: 0.0, y: rect.size.height);
        context?.scaleBy(x: 1.0, y: -1.0);
        let alphaMsk : CGImage? = context?.makeImage()
        context?.clear(rect)
        context?.clip(to: rect, mask: alphaMsk!)
        
        let colorSpace : CGColorSpace? = CGColorSpaceCreateDeviceRGB()
        let gradient = CGGradient.init(colorsSpace: colorSpace, colors: colors as CFArray, locations: nil)
        var startPoint = CGPoint.init(x: -rect.size.width, y: 0)
        var endPoint = CGPoint.init(x: 0, y: rect.size.height)
        
        if ConsoleBox.adding > rect.size.width * 2 {
            ConsoleBox.add = false
        }else if ConsoleBox.adding <= 0 {
            ConsoleBox.add = true
        }
        if ConsoleBox.add {
            ConsoleBox.adding += rect.size.width / 150
        }else{
            ConsoleBox.adding -= rect.size.width / 150
        }
        startPoint = CGPoint.init(x: startPoint.x + ConsoleBox.adding, y: startPoint.y)
        endPoint = CGPoint.init(x: endPoint.x + ConsoleBox.adding, y: endPoint.y)
        
        context?.drawLinearGradient(gradient!, start: startPoint, end: endPoint, options: [.drawsBeforeStartLocation,.drawsAfterEndLocation])
    }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容