美文网首页
iOS-UILabel文字渐变颜色扫描

iOS-UILabel文字渐变颜色扫描

作者: 情不知所起_一往而深 | 来源:发表于2022-01-19 17:33 被阅读0次

闲暇无事,整点骚操作。

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


渐变色扫描.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])
    }

}

相关文章

网友评论

      本文标题:iOS-UILabel文字渐变颜色扫描

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