跑马灯效果的Label

  • WSMarqueeLabel.h
#import 

NS_ASSUME_NONNULL_BEGIN


@interface WSMarqueeLabel : UIView
@property (nonatomic, assign) CGFloat speed;
@property (nonatomic, assign) CGFloat showTextTime;

@property (nullable, nonatomic, copy) NSString *text;
@property (nonatomic, strong) UIColor *textColor;
@property (nonatomic, strong) UIFont *font;

/// 开启滚动,默认为 YES。当 enableScroll 为 YES 时,如果文字超出,则自动开始滚动。设置为 NO,则不滚动。
/// 像普通 Label 一样会压缩显示。
@property (nonatomic, assign) BOOL enableScroll;

- (void)startAnimation;

@end

NS_ASSUME_NONNULL_END

  • WSMarqueeLabel.m

#import "WSMarqueeLabel.h"
#import "UIFont+CustomFont.h"

@interface WSMarqueeLabel ()

@property (nonatomic, strong) UILabel *label1;
@property (nonatomic, strong) UILabel *label2;
@property (nonatomic, strong) UIView *container;

@end


@implementation WSMarqueeLabel


- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initUI];
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (NSString *)text
{
    return self.label1.text;
}

- (void)setText:(NSString *)text
{
    self.label1.text = self.label2.text = text;
    [self layoutSubviews];
}

- (UIColor *)textColor
{
    return self.label1.textColor;
}

- (void)setTextColor:(UIColor *)textColor
{
    self.label1.textColor = self.label2.textColor = textColor;
}

- (UIFont *)font
{
    return self.label1.font;
}

- (void)setFont:(UIFont *)font
{
    self.label1.font = self.label2.font = font;
}

- (CGSize)intrinsicContentSize
{
    return self.label1.intrinsicContentSize;
}

#define WSMarqueeLabel_Text_Space 16

- (void)initUI
{
    _enableScroll = YES;
    
    self.label1 = [[UILabel alloc] init];
    self.label2 = [[UILabel alloc] init];
    self.label1.backgroundColor = [UIColor clearColor];
    self.label2.backgroundColor = [UIColor clearColor];


    self.textColor = [UIColor whiteColor];
    self.font = [UIFont wsfont_textRegular];

    UIView *container = [[UIView alloc] init];
    [container addSubview:self.label1];
    [container addSubview:self.label2];
    [self addSubview:container];
    self.container = container;

    self.layer.masksToBounds = YES;
    self.speed = 30;
    self.showTextTime = 2;

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startAnimation) name:UIApplicationDidBecomeActiveNotification object:nil];
}


- (void)startAnimation
{
    [self setNeedsLayout];
}

- (void)setSpeed:(CGFloat)speed
{
    if (speed == 0) {
        speed = 30;
    }
    _speed = speed;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    if (self.enableScroll) {
        [self.label1 sizeToFit];
        [self.label2 sizeToFit];
        CGFloat width = self.label1.frame.size.width;
        CGFloat height = self.label1.frame.size.height;
        self.label1.frame = CGRectMake(0, 0, width, height);
        self.label2.frame = CGRectMake(width + WSMarqueeLabel_Text_Space, 0, width, height);
        self.container.frame = CGRectMake(0, 0, width * 2 + WSMarqueeLabel_Text_Space, height);
        
        [self updateAndScroll];
    } else {
        self.label1.frame = self.bounds;
        self.container.frame = self.bounds;
        [self stopScroll];
    }
}

- (void)willMoveToWindow:(UIWindow *)newWindow
{
    if (newWindow == nil) {
        [self stopScroll];
    }
}

- (void)didMoveToWindow
{
    if (self.window == nil) {
        [self stopScroll];
    } else {
        [self updateAndScroll];
    }
}

- (void)stopScroll
{
    [self.container.layer removeAllAnimations];
    self.container.frame = CGRectMake(0, CGRectGetMinY(self.container.frame), CGRectGetWidth(self.container.frame), CGRectGetHeight(self.container.frame));
    self.label2.hidden = YES;
}

- (void)updateAndScroll
{
    [self.container.layer removeAllAnimations];
    self.container.frame = CGRectMake(0, CGRectGetMinY(self.container.frame), CGRectGetWidth(self.container.frame), CGRectGetHeight(self.container.frame));
    
    CGFloat labelWidth = self.label1.frame.size.width;
    if (labelWidth <= self.bounds.size.width || !self.enableScroll) {
        self.label2.hidden = YES;
        return;
    }
    self.label2.hidden = NO;
    
    CGRect fromRect = self.container.frame;
    CGRect toRect = fromRect;
    toRect.origin.x = 0 - labelWidth - WSMarqueeLabel_Text_Space;
    CGFloat duration = (labelWidth + WSMarqueeLabel_Text_Space) / self.speed;
    duration = fmin(duration, 20);
    [self repeatAnimationWithDuration:duration delay:1 fromRect:fromRect toRect:toRect];
}

- (void)repeatAnimationWithDuration:(CGFloat)duration delay:(CGFloat)delay fromRect:(CGRect)fromRect toRect:(CGRect)toRect
{
    self.container.frame = fromRect;
    [UIView animateWithDuration:duration delay:delay options:UIViewAnimationOptionCurveLinear animations:^{
        self.container.frame = toRect;
    } completion:^(BOOL finished) {
        if (finished) {
            [self updateAndScroll];
        }
    }];
}

- (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis
{
    return [self.label1 contentCompressionResistancePriorityForAxis:axis];
}
- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis
{
    [self.label1 setContentCompressionResistancePriority:priority forAxis:axis];
}

- (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis
{
    return [self.label1 contentHuggingPriorityForAxis:axis];
}
- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis
{
    [self.label1 setContentHuggingPriority:priority forAxis:axis];
}

@end

你可能感兴趣的:(跑马灯效果的Label)