閑暇無事母怜,整點騷操作。
想了半天缚柏,來個文字掃描苹熏,整點兒花的
先來一個效果圖
直接開整
干活
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])
}
}