给你们来张图看看先
简易的跑🏃.png
用 Masonry 布局,自己算Frame 也行,我把自己算Frame 注释掉了。
创建一个 自己的View 继承自 UIView 或者自己的 公共BaseView;
不多说上代码,走起
.h 这里的 "XPaoMaDView" 是我的自定义名称
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface XPaoMaDView : UIView
///
//- (instancetype)initWithFrame:(CGRect)frame withTitle:(NSString *)title;
///
- (void)withTitle:(NSString *)title;
///
- (void)start;
///
- (void)stop;
@end
NS_ASSUME_NONNULL_END
// 
#import "XPaoMaDView.h"
// 单次循环的时间
static const NSInteger animationDuration = 15;
// 文字大小
static const NSInteger textFont = 14.0;
@interface XPaoMaDView()
<
CAAnimationDelegate
>
{
    //左侧label的frame
    CGRect currentFrame;
    //右侧label的frame
    CGRect behindFrame;
    //存放左右label的数组
    NSMutableArray *labelArray;
    //label的高度
    CGFloat labelHeight;
    //是否为暂停状态
    BOOL isStop; 
}
@end
@implementation XPaoMaDView
/*
- (instancetype)initWithFrame:(CGRect)frame withTitle:(NSString *)title
{
    self = [super initWithFrame:frame];
    if (self) {
        self.clipsToBounds = YES;
        //
        CGFloat viewHeight = frame.size.height;
        labelHeight = viewHeight;
        //
        UILabel *myLable = [[UILabel alloc] init];
        myLable.text = title;
        myLable.font = [UIFont systemFontOfSize:textFont];
        myLable.backgroundColor = [UIColor orangeColor];
        //计算文本的宽度
        CGFloat calcuWidth = [self widthForTextString:title height:labelHeight fontSize:textFont];
        //这两个frame很重要 分别记录的是左右两个label的frame 而且后面也会需要到这两个frame
        currentFrame = CGRectMake(0, 0, calcuWidth, labelHeight);
        behindFrame = CGRectMake(currentFrame.origin.x + currentFrame.size.width, 0, calcuWidth, labelHeight);
        myLable.frame = currentFrame;
        [self addSubview:myLable];
        labelArray  = [NSMutableArray arrayWithObject:myLable];
        //如果文本的宽度大于视图的宽度才开始跑
        if (calcuWidth > frame.size.width)
        {
            UILabel *behindLabel = [[UILabel alloc] init];
            behindLabel.frame = behindFrame;
            behindLabel.text = title;
            behindLabel.font = [UIFont systemFontOfSize:textFont];
            behindLabel.backgroundColor = [UIColor orangeColor];
            [labelArray addObject:behindLabel];
            [self addSubview:behindLabel];
            
            [self doCustomAnimation];
        }
    }
    return self;
}
*/
///
- (void)withTitle:(NSString *)title
{
// 注意 layoutIfNeeded 这里使用的是 Masonry  要加这句话,不然你懂得
    [self layoutIfNeeded]; //
    self.clipsToBounds = YES;
    //
    CGFloat viewHeight = self.frame.size.height;
    labelHeight = viewHeight;
    //
    UILabel *myLable = [[UILabel alloc] init];
    myLable.text = title;
    myLable.font = [UIFont systemFontOfSize:textFont];
    myLable.backgroundColor = [UIColor orangeColor];
    //计算文本的宽度
    CGFloat calcuWidth = [self widthForTextString:title height:labelHeight fontSize:textFont];
    //这两个frame很重要 分别记录的是左右两个label的frame 而且后面也会需要到这两个frame
    currentFrame = CGRectMake(0, 0, calcuWidth, labelHeight);
    behindFrame = CGRectMake(currentFrame.origin.x + currentFrame.size.width, 0, calcuWidth, labelHeight);
    myLable.frame = currentFrame;
    [self addSubview:myLable];
    labelArray  = [NSMutableArray arrayWithObject:myLable];
    //如果文本的宽度大于视图的宽度才开始跑
    if (calcuWidth > self.frame.size.width)
    {
        UILabel *behindLabel = [[UILabel alloc] init];
        behindLabel.frame = behindFrame;
        behindLabel.text = title;
        behindLabel.font = [UIFont systemFontOfSize:textFont];
        behindLabel.backgroundColor = [UIColor orangeColor];
        [labelArray addObject:behindLabel];
        [self addSubview:behindLabel];
        
        [self doCustomAnimation];
    }
}
- (void)doCustomAnimation
{
    //取到两个label
    UILabel *lableOne = [labelArray firstObject];
    UILabel *lableTwo = [labelArray lastObject];
    
    [lableOne.layer removeAnimationForKey:@"LabelOneAnimation"];
    [lableTwo.layer removeAnimationForKey:@"LabelTwoAnimation"];
    
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.values = @[
        [NSValue valueWithCGPoint:CGPointMake(lableOne.frame.origin.x + currentFrame.size.width / 2, lableOne.frame.origin.y + labelHeight / 2)],
        [NSValue valueWithCGPoint:CGPointMake(lableOne.frame.origin.x - currentFrame.size.width / 2, lableOne.frame.origin.y + labelHeight / 2)]
    ];
    animation.duration = animationDuration;
    animation.delegate = self;
    animation.calculationMode = kCAAnimationLinear;
    animation.removedOnCompletion = NO;
    [lableOne.layer addAnimation:animation forKey:@"LabelOneAnimation"];
    
    CAKeyframeAnimation *animationTwo = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animationTwo.values = @[
        [NSValue valueWithCGPoint:CGPointMake(lableTwo.frame.origin.x + currentFrame.size.width / 2, lableTwo.frame.origin.y + labelHeight / 2)],
        [NSValue valueWithCGPoint:CGPointMake(lableTwo.frame.origin.x - currentFrame.size.width / 2, lableTwo.frame.origin.y + labelHeight / 2)]
    ];
    animationTwo.duration = animationDuration;
    animationTwo.delegate = self;
    animationTwo.removedOnCompletion = NO;
    animationTwo.calculationMode = kCAAnimationLinear;
    [lableTwo.layer addAnimation:animationTwo forKey:@"LabelTwoAnimation"];
    
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    
    UILabel *lableOne = [labelArray firstObject];
    UILabel *lableTwo = [labelArray lastObject];
    if (flag && anim == [lableOne.layer animationForKey:@"LabelOneAnimation"])
    {
        //两个label水平相邻摆放 内容一样 label1为初始时展示的 label2位于界面的右侧,未显示出来
        //当完成动画时,即第一个label在界面中消失,第二个label位于第一个label的起始位置时,把第一个label放置到第二个label的初始位置
        lableOne.frame = behindFrame;
        lableTwo.frame = currentFrame;
        //在数组中将第一个label放置到右侧,第二个label放置到左侧(因为此时展示的就是labelTwo)
        [labelArray replaceObjectAtIndex:1 withObject:lableOne];
        [labelArray replaceObjectAtIndex:0 withObject:lableTwo];
        
        [self doCustomAnimation];
    }
    
}
- (CGFloat) widthForTextString:(NSString *)tStr height:(CGFloat)tHeight fontSize:(CGFloat)tSize
{
    NSDictionary *dict = @{NSFontAttributeName : [UIFont systemFontOfSize:tSize]};
    CGRect rect = [tStr boundingRectWithSize:CGSizeMake(MAXFLOAT, tHeight) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil];
    return rect.size.width + 5;
}
- (void)start
{
    if (isStop)
    {
        UILabel *lableOne = [labelArray firstObject];
        [self resumeLayer:lableOne.layer];
        
        UILabel *lableTwo = [labelArray lastObject];
        [self resumeLayer:lableTwo.layer];
        
        isStop = NO;
    }
}
- (void)stop
{
    if (!isStop)
    {
        UILabel *lableOne = [labelArray firstObject];
        [self pauseLayer:lableOne.layer];
        
        UILabel *lableTwo = [labelArray lastObject];
        [self pauseLayer:lableTwo.layer];
        
        isStop = YES;
    }
}
//暂停动画
- (void)pauseLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    layer.speed = 0;
    layer.timeOffset = pausedTime;
}
//恢复动画
- (void)resumeLayer:(CALayer*)layer
{
    //当你是停止状态时,则恢复
    if (isStop)
    {
        CFTimeInterval pauseTime = [layer timeOffset]; 
        layer.speed = 1.0;
        layer.timeOffset = 0.0;
        layer.beginTime = 0.0;
        CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pauseTime;
        layer.beginTime = timeSincePause;
    }
    
}
@end
使用方法:
#import "XPaoMaDView.h"
///
@property (nonatomic, strong) XPaoMaDView *paomadengView;
// --------------- 
- (void)这里就不要Copy了viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    调用UI啦🌶
    [self addUI];
    [self addBtnUI];
}
// --------------- 
#pragma mark ----- lzy
- (XPaoMaDView *)paomadengView
{
    if (!_paomadengView) {
        _paomadengView = [[XPaoMaDView alloc] init];
    }
    return _paomadengView;
}
/// 添加 UI 
- (void)addUI
{
    [self.view addSubview:self.paomadengView];
    [self.paomadengView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(RATIOA(20));
        make.right.mas_equalTo(RATIOA(-20));
        make.centerX.centerY.mas_equalTo(0);
        make.height.mas_equalTo(RATIOA(44));
    }];
    self.paomadengView.backgroundColor = [UIColor 你给个颜色看看];
    
    [self.paomadengView withTitle:@"1、这是个跑马灯,不信?你看~它跑起来了~~~2、这是个跑马灯,不信?你看~它跑起来了~~~"];
}
- (void)addBtnUI
{
    NSArray *ary = @[@"开始", @"暂停"];
    for (int i = 0; i < 2; i++) {
        UIButton *btn = [[UIButton alloc] init];
        [btn addTarget:self action:@selector(ActionClick:) forControlEvents:(UIControlEventTouchUpInside)];
        [btn setTitle:ary[i] forState:(UIControlStateNormal)];
        [btn setBackgroundColor:[UIColor 你给个颜色看看]];
        btn.tag = 100 + i;
        [self.view addSubview:btn];
        
        [btn mas_makeConstraints:^(MASConstraintMaker *make) {
            if (i == 0) {
                make.right.mas_equalTo(self.view.mas_centerX).offset(RATIOA(-20));
            } else {
                make.left.mas_equalTo(self.view.mas_centerX).offset(RATIOA(20));
            }
            make.top.mas_equalTo(RATIOA(100));
            make.height.mas_equalTo(RATIOA(44));
            make.width.mas_equalTo(RATIOA(100));
        }];
    }
    
}
- (void)ActionClick:(UIButton *)button
{
    NSInteger index = button.tag - 100;
    
    if (index == 0)
    {
        [self.paomadengView start];
    }
    else
    {
        [self.paomadengView stop];
    }
    
}













网友评论