Files
featherVoice/QXLive/Tools/CKShimmerLabel.m

325 lines
10 KiB
Mathematica
Raw Normal View History

2025-08-08 10:49:36 +08:00
//
// CKShimmerLabel.m
// CKShimmerLabel
//
// Created by caokun on 16/8/16.
// Copyright © 2016 caokun. All rights reserved.
//
#import "CKShimmerLabel.h"
@interface CKShimmerLabel ()
@property (strong, nonatomic) UILabel *maskLabel;
@property (strong, nonatomic) CAGradientLayer *maskLayer;
@property (assign, nonatomic) BOOL isPlaying; //
@property (assign, nonatomic) CGSize charSize; // size
@property (assign, nonatomic) CATransform3D startT, endT; // [startT, endT]
@property (strong, nonatomic) CABasicAnimation *translate; //
@property (strong, nonatomic) CABasicAnimation *alphaAni; // alpha
@end
@implementation CKShimmerLabel
- (instancetype)init {
if (self = [super init]) {
self.frame = CGRectMake(0, 0, 60, 30);
[self myInit];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self myInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self myInit];
}
return self;
}
- (void)myInit {
[self addSubview:self.contentLabel];
[self addSubview:self.maskLabel];
self.layer.masksToBounds = true;
self.isPlaying = false;
self.startT = CATransform3DIdentity;
self.endT = CATransform3DIdentity;
self.charSize = CGSizeMake(0, 0);
self.shimmerType = ST_LeftToRight;
self.repeat = true;
self.shimmerWidth = 20;
self.shimmerRadius = 20;
self.shimmerColor = [UIColor whiteColor];
self.durationTime = 2;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)layoutSubviews {
[super layoutSubviews];
//
self.contentLabel.frame = self.bounds;
self.maskLabel.frame = self.bounds;
self.maskLayer.frame = CGRectMake(0, 0, self.charSize.width, self.charSize.height);
}
#pragma mark - set, get
- (UILabel *)contentLabel {
if (_contentLabel == nil) {
_contentLabel = [[UILabel alloc] initWithFrame:self.bounds];
_contentLabel.font = [UIFont systemFontOfSize:17];
_contentLabel.textColor = [UIColor darkGrayColor];
}
return _contentLabel;
}
- (UILabel *)maskLabel {
if (_maskLabel == nil) {
_maskLabel = [[UILabel alloc] initWithFrame:self.bounds];
_maskLabel.font = [UIFont systemFontOfSize:17];
_maskLabel.textColor = [UIColor darkGrayColor];
_maskLabel.hidden = true;
}
return _maskLabel;
}
- (CALayer *)maskLayer {
if (_maskLayer == nil) {
_maskLayer = [[CAGradientLayer alloc] init];
_maskLayer.backgroundColor = [UIColor clearColor].CGColor;
[self freshMaskLayer];
}
return _maskLayer;
}
- (void)setText:(NSString *)text {
if (_text == text) return ;
_text = text;
self.contentLabel.text = text;
self.charSize = [self.contentLabel.text boundingRectWithSize:self.contentLabel.frame.size options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : self.contentLabel.font} context:nil].size;
[self update];
}
- (void)setFont:(UIFont *)font {
if (_font == font) return ;
_font = font;
self.contentLabel.font = font;
self.charSize = [self.contentLabel.text boundingRectWithSize:self.contentLabel.frame.size options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : self.contentLabel.font} context:nil].size;
[self update];
}
- (void)setTextColor:(UIColor *)textColor {
if (_textColor == textColor) return ;
_textColor = textColor;
self.contentLabel.textColor = textColor;
[self update];
}
- (void)setAttributedText:(NSAttributedString *)attributedText {
if (_attributedText == attributedText) return ;
_attributedText = attributedText;
self.contentLabel.attributedText = attributedText;
[self update];
}
- (void)setNumberOfLines:(NSInteger)numberOfLines {
if (_numberOfLines == numberOfLines) return ;
_numberOfLines = numberOfLines;
self.contentLabel.numberOfLines = numberOfLines;
[self update];
}
- (void)setShimmerType:(ShimmerType)shimmerType {
if (_shimmerType == shimmerType) return ;
_shimmerType = shimmerType;
[self update];
}
- (void)setRepeat:(BOOL)repeat {
if (_repeat == repeat) return ;
_repeat = repeat;
[self update];
}
- (void)setShimmerWidth:(CGFloat)shimmerWidth {
if (_shimmerWidth == shimmerWidth) return ;
_shimmerWidth = shimmerWidth;
[self update];
}
- (void)setShimmerRadius:(CGFloat)shimmerRadius {
if (_shimmerRadius == shimmerRadius) return ;
_shimmerRadius = shimmerRadius;
[self update];
}
- (void)setShimmerColor:(UIColor *)shimmerColor {
if (_shimmerColor == shimmerColor) return ;
_shimmerColor = shimmerColor;
self.maskLabel.textColor = shimmerColor;
[self update];
}
- (void)setDurationTime:(NSTimeInterval)durationTime {
if (_durationTime == durationTime) return ;
_durationTime = durationTime;
[self update];
}
- (void)update {
if (self.isPlaying) { //
[self stopShimmer];
[self startShimmer];
}
}
// maskLayer , transform
- (void)freshMaskLayer {
if (self.shimmerType != ST_ShimmerAll) {
_maskLayer.backgroundColor = [UIColor clearColor].CGColor;
_maskLayer.startPoint = CGPointMake(0, 0.5);
_maskLayer.endPoint = CGPointMake(1, 0.5);
_maskLayer.colors = @[(id)[UIColor clearColor].CGColor, (id)[UIColor clearColor].CGColor, (id)[UIColor whiteColor].CGColor, (id)[UIColor whiteColor].CGColor, (id)[UIColor clearColor].CGColor, (id)[UIColor clearColor].CGColor];
CGFloat w = 1.0;
CGFloat sw = 1.0;
if (self.charSize.width >= 1) {
w = self.shimmerWidth / self.charSize.width * 0.5;
sw = self.shimmerRadius / self.charSize.width;
}
_maskLayer.locations = @[@(0.0), @(0.5 - w - sw), @(0.5 - w), @(0.5 + w), @(0.5 + w + sw), @(1)];
CGFloat startX = self.charSize.width * (0.5 - w - sw);
CGFloat endX = self.charSize.width * (0.5 + w + sw);
self.startT = CATransform3DMakeTranslation(-endX, 0, 1);
self.endT = CATransform3DMakeTranslation(self.charSize.width - startX, 0, 1);
} else {
_maskLayer.backgroundColor = self.shimmerColor.CGColor;
_maskLayer.colors = nil;
_maskLayer.locations = nil;
}
}
#pragma mark -
- (void)copyLabel:(UILabel *)dLabel from:(UILabel *)sLabel {
dLabel.attributedText = self.attributedText;
dLabel.text = self.text;
dLabel.font = self.font;
dLabel.numberOfLines = self.numberOfLines;
}
- (CABasicAnimation *)translate {
if (_translate == nil) {
_translate = [CABasicAnimation animationWithKeyPath:@"transform"];
}
_translate.removedOnCompletion = NO;
_translate.duration = self.durationTime;
_translate.repeatCount = self.repeat == true ? MAXFLOAT : 0;
_translate.autoreverses = self.shimmerType == ST_AutoReverse ? true : false;
return _translate;
}
- (CABasicAnimation *)alphaAni {
if (_alphaAni == nil) {
_alphaAni = [CABasicAnimation animationWithKeyPath:@"opacity"];
_alphaAni.repeatCount = MAXFLOAT;
_alphaAni.autoreverses = true;
_alphaAni.removedOnCompletion = NO;
_alphaAni.fromValue = @(0.0);
_alphaAni.toValue = @(1.0);
}
_alphaAni.duration = self.durationTime;
return _alphaAni;
}
- (void)startShimmer {
dispatch_async(dispatch_get_main_queue(), ^{
// 线runloop isPlaying 线
// dispatch_async() strong block
if (self.isPlaying == true) return ;
self.isPlaying = true;
[self copyLabel:self.maskLabel from:self.contentLabel];
self.maskLabel.hidden = false;
// [self.layer addSublayer:self.maskLayer];
[self.maskLayer removeFromSuperlayer];
[self freshMaskLayer];
[self.maskLabel.layer addSublayer:self.maskLayer];
self.maskLabel.layer.mask = self.maskLayer;
switch (self.shimmerType) {
case ST_LeftToRight: {
self.maskLayer.transform = self.startT;
self.translate.fromValue = [NSValue valueWithCATransform3D:self.startT];
self.translate.toValue = [NSValue valueWithCATransform3D:self.endT];
[self.maskLayer removeAllAnimations];
[self.maskLayer addAnimation:self.translate forKey:@"start"];
break;
}
case ST_RightToLeft: {
self.maskLayer.transform = self.endT;
self.translate.fromValue = [NSValue valueWithCATransform3D:self.endT];
self.translate.toValue = [NSValue valueWithCATransform3D:self.startT];
[self.maskLayer removeAllAnimations];
[self.maskLayer addAnimation:self.translate forKey:@"start"];
break;
}
case ST_AutoReverse : {
self.maskLayer.transform = self.startT;
self.translate.fromValue = [NSValue valueWithCATransform3D:self.startT];
self.translate.toValue = [NSValue valueWithCATransform3D:self.endT];
[self.maskLayer removeAllAnimations];
[self.maskLayer addAnimation:self.translate forKey:@"start"];
break;
}
case ST_ShimmerAll : {
self.maskLayer.transform = CATransform3DIdentity;
[self.maskLayer removeAllAnimations];
[self.maskLayer addAnimation:self.alphaAni forKey:@"start"];
break;
}
default: break;
}
});
}
- (void)stopShimmer {
dispatch_async(dispatch_get_main_queue(), ^{
if (self.isPlaying == false) return ;
self.isPlaying = false;
[self.maskLayer removeAllAnimations];
[self.maskLayer removeFromSuperlayer];
self.maskLabel.hidden = true;
});
}
@end