iOS开发造小轮子 | 跑马灯

作者: Lol刀妹 | 来源:发表于2017-08-22 16:43 被阅读1229次
    IU大法

    效果

    实际项目中很常见的效果,如下:

    效果.gif

    思路

    让label的宽度自适应内容,然后放到一个背景view上,背景view的clipsToBounds开启。持续的改变label的frame,当label末端的x坐标为0时,调整其首端x坐标。如下,不停的执行这段代码:

    /** 刷新跑马灯label的位置 */
    - (void)refreshMarqueeLabelFrame {
        _marqueeLabel.maxX -= 0.3;
        if (_marqueeLabel.maxX <= 0) {
            _marqueeLabel.x = self.width - 41 - 38;
        }
    }
    

    代码

    代码没亮点,关键是思路

    @implementation CQMarqueeView{
        UILabel *_marqueeLabel;
        /** 控制跑马灯的timer */
        NSTimer *_timer;
    }
    
    #pragma mark - 构造方法
    - (instancetype)initWithFrame:(CGRect)frame {
        if (self = [super initWithFrame:frame]) {
            // UI搭建
            [self setUpUI];
        }
        return self;
    }
    
    #pragma mark - UI搭建
    /** UI搭建 */
    - (void)setUpUI {
        self.backgroundColor = [UIColor colorWithHexString:@"fff4d8"];
        
        //------- 左边的喇叭 -------//
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(13, 9, 16, 12)];
        [self addSubview:imageView];
        imageView.image = [UIImage imageNamed:@"volume-marquee"];
        
        //------- 右边的关闭按钮 -------//
        UIButton *closeButton = [[UIButton alloc] initWithFrame:CGRectMake(self.width - 33, 0, 30, 30)];
        [self addSubview:closeButton];
        [closeButton setImage:[UIImage imageNamed:@"close-marquee"] forState:UIControlStateNormal];
        [closeButton setImageEdgeInsets:UIEdgeInsetsMake(9, 9, 9, 9)];
        [closeButton addTarget:self action:@selector(closeButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
        
        //------- marquee View -------//
        
        // 背景
        UIView *marqueeBgView = [[UIView alloc] initWithFrame:CGRectMake(41, 0, self.width - 41 - 38, self.height)];
        [self addSubview:marqueeBgView];
        marqueeBgView.clipsToBounds = YES;
        
        // marquee label
        _marqueeLabel = [[UILabel alloc] initWithFrame:marqueeBgView.bounds];
        [marqueeBgView addSubview:_marqueeLabel];
        _marqueeLabel.textColor = [UIColor colorWithHexString:@"ff6666"];
        _marqueeLabel.font = [UIFont systemFontOfSize:13];
    }
    
    #pragma mark - 关闭按钮点击
    /** 关闭按钮点击 */
    - (void)closeButtonClicked:(UIButton *)sender {
        if (_timer) {
            [_timer invalidate];
            _timer = nil;
        }
        
        if ([self.delegate respondsToSelector:@selector(marqueeView:closeButtonDidClick:)]) {
            [self.delegate marqueeView:self closeButtonDidClick:sender];
        }
    }
    
    #pragma mark - 赋值跑马灯文字
    /** 赋值跑马灯文字 */
    - (void)setMarqueeText:(NSString *)marqueeText {
        _marqueeText = marqueeText;
        
        _marqueeLabel.text = _marqueeText;
        [_marqueeLabel sizeToFit];
        _marqueeLabel.centerY = self.height / 2;
        
        if (_timer) {
            [_timer invalidate];
            _timer = nil;
        }
        
        // 从最右边开始跑
        _marqueeLabel.x = self.width - 41 - 38;
        
        _timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(refreshMarqueeLabelFrame) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
    }
    
    /** 刷新跑马灯label的位置 */
    - (void)refreshMarqueeLabelFrame {
        _marqueeLabel.x -= 0.3;
        if (_marqueeLabel.maxX <= 0) {
            _marqueeLabel.x = self.width - 41 - 38;
        }
    }
    

    注意

    timer的频率设置高点,步伐设置低点,可以让动画更连贯。不过貌似timer的interval最低只能设置为0.01s

    需求变了。。。

    今天产品那边要求能展示多条信息,并且一条信息跑完后再接着跑另一条信息。。。
    我表示早已习以为常,然后10秒之内做出响应:
    1.既然是多条信息,那数据源肯定从原来的string变成了array。

    /** 跑马灯展示的文本数组 */
    @property (nonatomic, strong) NSArray *marqueeTextArray;
    

    2.跑完一条信息后跑下一条,跑完所有信息后又从第一条开始跑

    /** 改变label位置 */
    - (void)refreshMarqueeLabelFrame {
        static int i = 0;
        _marqueeLabel.maxX -= 0.3;
        if (_marqueeLabel.maxX <= 0) { // 当前信息跑完
            i ++;
            _marqueeLabel.x = self.width - 41 - 38; // 回到最右边
            // 取模是关键
            [self setMarqueeText:_marqueeTextArray[i % self.marqueeTextArray.count]];
        }
    }
    

    详情可参考demo

    需求变更后的demo

    上面演示的demo


    2017年9月11日更新

    将NSTimer换为CADisplayLink(每秒60次)。
    注:在模拟器上运行看起有点卡,但真机上很流畅。😎

    相关文章

      网友评论

      本文标题:iOS开发造小轮子 | 跑马灯

      本文链接:https://www.haomeiwen.com/subject/lvlldxtx.html