跑马灯Label网上有不少个作法,其实基本原理很简单,作法也不少样,能够是一个scrollView上面放两个label,而后用定时器定时执行动画;也有的是用定时器,在短暂的间隔时间内执行把文字drawInRect方法。性能
最开始我是用上面说的第一种方法,可是发现每次定时器执行完一次动画,下一次动画执行之间,总会有个很短暂但很明显感受到的停顿,这和我想要的效果不一样;而执行文字drawInRect方法是比较耗cpu的,第二个方法对性能消耗太大了;既然最终都是执行动画,那么为何不让动画本身来负责本身的开始和结束和循环,而让定时器都不用参与?字体
个人作法里主要用了CATextLayer和CABasicAnimation,CATextLayer是用来绘制文本,CABasicAnimation用来执行动画,CATextLayer和UILabel很类似,在iOS6以前,UILabel是经过Webkit来实现绘制的,因此当不少文字的时候性能方面就有压力,而CATextLayer是使用了CoreText,渲染很是快。动画
CATextLayer有个string的属性,这个属性能够是NSString也能够是NSAttributedString,但当是NSAttributedString的时候,相应的像font属性之类的属性就没有效果。atom
我在使用CATextLayer的时候,碰上了一点麻烦,就是字体,CATextLayer使用的不是UIFont,而是CTFontRef和CGFontRef或者给字体的名称,这三个方法我都试过,但在最终效果上对比一样文本和字体的UILabel,计算出来的宽度老是有小误差,因此最终使用了string属性是NSAttributedString对象(这里我的猜想,可能即便string属性是NSString对象,最终也是转换为NSAttributedString来使用)。spa
下面是个人作法code
@interface AutoScrollLabel : UIView @property (nonatomic, copy) NSString* text; @property (nonatomic, assign) CGFloat fontSize; @property (nonatomic, strong) UIFont* font; @property (nonatomic, strong) UIColor* textColor; @property (nonatomic, assign) CGFloat speed; @property (nonatomic, copy) NSAttributedString* attributedText; @end
#import <CoreText/CoreText.h> @interface AutoScrollLabel() { CATextLayer* _firstLayer; CATextLayer* _secondLayer; } @end @implementation AutoScrollLabel - (instancetype)init { self = [super init]; if (self) { [self commonInit]; } return self; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self commonInit]; } return self; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self commonInit]; } return self; } - (void)commonInit { _firstLayer = [[CATextLayer alloc] init]; _firstLayer.bounds = CGRectZero; _firstLayer.position = CGPointZero; _firstLayer.alignmentMode = kCAAlignmentCenter; _firstLayer.foregroundColor = [UIColor blackColor].CGColor; _firstLayer.contentsScale = [UIScreen mainScreen].scale; //contentsScale的指定为了适配retian屏 [self.layer addSublayer:_firstLayer]; _secondLayer = [[CATextLayer alloc] init]; _secondLayer.bounds = CGRectZero; _secondLayer.position = CGPointZero; _secondLayer.alignmentMode = kCAAlignmentCenter; _secondLayer.foregroundColor = [UIColor blackColor].CGColor; _secondLayer.contentsScale = [UIScreen mainScreen].scale; [self.layer addSublayer:_secondLayer]; _fontSize = 15.0f; _font = [UIFont systemFontOfSize:_fontSize]; _textColor = [UIColor blackColor]; self.layer.masksToBounds = YES; } - (void)setAttributedText:(NSAttributedString *)attributedText { _attributedText = attributedText; _firstLayer.string = attributedText; _secondLayer.string = attributedText; } - (void)drawRect:(CGRect)rect { if (_attributedText == nil) { _font = [UIFont systemFontOfSize:_fontSize]; _attributedText = [[NSAttributedString alloc] initWithString:_text attributes:@{NSFontAttributeName:_font, NSForegroundColorAttributeName:_textColor}]; _firstLayer.string = _attributedText; _secondLayer.string = _attributedText; } NSRange range = NSMakeRange(0, _attributedText.length); CGSize textSize = [_attributedText.string boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:[_attributedText attributesAtIndex:0 effectiveRange:&range] context:nil].size; if (textSize.width < rect.size.width) { textSize.width = rect.size.width; } // 在计算出的文本宽度后加入10的宽度做为两个文本之间的间隔 _firstLayer.bounds = CGRectMake(0, 0, textSize.width + 10, textSize.height); _firstLayer.position = CGPointMake(textSize.width / 2 + 5, rect.size.height / 2); _secondLayer.bounds = CGRectMake(0, 0, textSize.width + 10, textSize.height); _secondLayer.position = CGPointMake(textSize.width + 10 + textSize.width / 2 + 5, rect.size.height / 2); // 文本宽度超过区域宽度才有滚动动画 if (textSize.width > rect.size.width) { if (_speed <= 0) { _speed = textSize.width / 30; } CABasicAnimation* firstAnimation = [CABasicAnimation animationWithKeyPath:@"position"]; firstAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(_firstLayer.frame.origin.x - textSize.width / 2 - 5, rect.size.height / 2)]; firstAnimation.duration = _speed; firstAnimation.repeatCount = HUGE_VALF; [_firstLayer addAnimation:firstAnimation forKey:@"FirstAnimation"]; CABasicAnimation* secondAnimation = [CABasicAnimation animationWithKeyPath:@"position"]; secondAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(textSize.width / 2 + 5, rect.size.height / 2)]; secondAnimation.duration = _speed; secondAnimation.repeatCount = HUGE_VALF; [_secondLayer addAnimation:secondAnimation forKey:@"SecondAnimation"]; } } @end
用xib生成的实例也是有效
对象
@property (weak, nonatomic) IBOutlet AutoScrollLabel *autoScrollLabel; /////////////只是做为分割线//////////////////// _autoScrollLabel.text = @"jojo_text店铺"; _autoScrollLabel.fontSize = 17;
但跟CATextLayer同样,若是指定了attributedText属性,那么其余属性设置就无需了。animation