iOS-UILabel文字漸變顏色掃描

閑暇無事母怜,整點騷操作。

想了半天缚柏,來個文字掃描苹熏,整點兒花的
先來一個效果圖


漸變色掃描.gif

直接開整

干活

Objective-C、Swift實現(xiàn)思路是一樣的币喧,就語言區(qū)別轨域,文章最后附代碼
先想想效果,一道斜杠的漸變顏色區(qū)間杀餐,勻速往右邊掃描過去干发,然后再回來。
然后開始想象思路史翘。

首先

言語表達不出來枉长,我淦!總之就是需要一塊漸變背景左右晃來晃去~
直接上代碼

第一步

創(chuàng)建一個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、創(chuàng)建漸變的背景

既然要左右晃動钻蹬,那就默認把這個漸變背景的長度設置為label長度的三倍吼蚁,最左邊和最右邊為字體原有顏色,中間為漸變色问欠,當這個漸變背景左右滑動時肝匆,也就實現(xiàn)了漸變背景的掃描效果。

- (void)drawRect:(CGRect)rect {
    //每次刷新的增量溅潜,設置成靜態(tài)變量防止每次都被初始化
    static CGFloat adding = 0;
    //往左還是往右,YES為有薪伏,NO為左
    static BOOL add = YES;
    /*
     coding
    */
    //創(chuàng)建一個漸變色顏色空間
    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滚澜、創(chuàng)建每幀調(diào)用CADisplayLink

讓每幀都去調(diào)用setNeedsDisplay,重新繪制label

/// 開始動畫掃描
- (void)startTextGradient {
    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeState)];
    if (@available(iOS 10, *)) {
        //每秒執(zhí)行的次數(shù)嫁怀,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借浊、觸發(fā)條件

創(chuàng)建一個公有屬性gradientColor,存儲設置的漸變色數(shù)組
setter方法里面做判斷
如果設置的為空萝招,代表不需要漸變蚂斤,所以直接移除正在執(zhí)行的掃描動畫
如果有值,那就啟動掃描


當沒有設置漸變顏色的時候槐沼,我們就需要默認顏色為label設置的顏色曙蒸,因為漸變,所以要設置成兩個相同的顏色岗钩,讓它看起來沒有漸變效果纽窟。
所以再創(chuàng)建一個colors的數(shù)組存儲轉換為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, *)) {
        //每秒執(zhí)行的次數(shù),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])
    }

}

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臂港,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子视搏,更是在濱河造成了極大的恐慌审孽,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浑娜,死亡現(xiàn)場離奇詭異佑力,居然都是意外死亡,警方通過查閱死者的電腦和手機棚愤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門搓萧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宛畦,你說我怎么就攤上這事瘸洛。” “怎么了次和?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵反肋,是天一觀的道長。 經(jīng)常有香客問我踏施,道長石蔗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任畅形,我火速辦了婚禮养距,結果婚禮上,老公的妹妹穿的比我還像新娘日熬。我一直安慰自己棍厌,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耘纱,像睡著了一般敬肚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上束析,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天艳馒,我揣著相機與錄音,去河邊找鬼员寇。 笑死弄慰,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的丁恭。 我是一名探鬼主播曹动,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼牲览!你這毒婦竟也來了墓陈?” 一聲冷哼從身側響起回官,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤儒旬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后雹嗦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庸毫,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡仔拟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了飒赃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片利花。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖载佳,靈堂內(nèi)的尸體忽然破棺而出炒事,到底是詐尸還是另有隱情,我是刑警寧澤蔫慧,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布挠乳,位于F島的核電站,受9級特大地震影響姑躲,放射性物質(zhì)發(fā)生泄漏睡扬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一黍析、第九天 我趴在偏房一處隱蔽的房頂上張望卖怜。 院中可真熱鬧,春花似錦阐枣、人聲如沸马靠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虑粥。三九已至,卻和暖如春宪哩,著一層夾襖步出監(jiān)牢的瞬間娩贷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工锁孟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留彬祖,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓品抽,卻偏偏與公主長得像储笑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子圆恤,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容