iOS-UILabel文字漸變顏色掃描

閑暇無事,整點(diǎn)騷操作。

想了半天,來個(gè)文字掃描,整點(diǎn)兒花的
先來一個(gè)效果圖


漸變色掃描.gif

直接開整

干活

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

首先

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

第一步

創(chuàng)建一個(gè)UILabel的子類,重寫drawRect

1、正常的重繪
- (void)drawRect:(CGRect)rect {
    /*
    coding
    */
    //獲取上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //復(fù)制文本的對其格式和字體
    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];
    //重設(shè)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)建漸變的背景

既然要左右晃動,那就默認(rèn)把這個(gè)漸變背景的長度設(shè)置為label長度的三倍,最左邊和最右邊為字體原有顏色,中間為漸變色,當(dāng)這個(gè)漸變背景左右滑動時(shí),也就實(shí)現(xiàn)了漸變背景的掃描效果。

- (void)drawRect:(CGRect)rect {
    //每次刷新的增量,設(shè)置成靜態(tài)變量防止每次都被初始化
    static CGFloat adding = 0;
    //往左還是往右,YES為有,NO為左
    static BOOL add = YES;
    /*
     coding
    */
    //創(chuàng)建一個(gè)漸變色顏色空間
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)self.colors, NULL);
    
    //設(shè)置漸變色的起點(diǎn)坐標(biāo)和終點(diǎn)坐標(biāo)
    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;
    }
    //增量設(shè)置為字體寬度的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)建一個(gè)公有屬性gradientColor,存儲設(shè)置的漸變色數(shù)組
setter方法里面做判斷
如果設(shè)置的為空,代表不需要漸變,所以直接移除正在執(zhí)行的掃描動畫
如果有值,那就啟動掃描


當(dāng)沒有設(shè)置漸變顏色的時(shí)候,我們就需要默認(rèn)顏色為label設(shè)置的顏色,因?yàn)闈u變,所以要設(shè)置成兩個(gè)相同的顏色,讓它看起來沒有漸變效果。
所以再創(chuàng)建一個(gè)colors的數(shù)組存儲轉(zhuǎn)換為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;
}

這樣一個(gè)文字漸變色掃描就完成了
用法

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;
//時(shí)間幀
@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])
    }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容