闲暇无事,整点骚操作。
想了半天,来个文字扫描,整点儿花的
先来一个效果图
直接开整
干活
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])
}
}