设为首页 加入收藏

TOP

【IOS】自定义可点击的多文本跑马灯YFRollingLabel(一)
2017-10-13 10:33:19 】 浏览:5851
Tags:IOS 定义 点击 文本 马灯 YFRollingLabel

需求

项目中需要用到跑马灯来仅展示一条消息,长度合适则不滚动,过长则循环滚动。

虽然不是我写的,但看了看代码,是在一个UIView里面放入两个UILabel,

在前一个快结束的时候,另一个显示。然而点击处理的 确是UIView的点击事件。    

 

然而看到比如地铁、公交里面的跑马灯是分了很多段显示的。虽然说可以将多段合并为一段来显示,

但是如果各个需要点击事件又该如何处理呢?于是我来自己实现可点击的多段跑马灯。

所以这篇随笔我要实现的跑马灯包含下面这种效果:(图中有5段   点击不同文本可触发相应的事件)

 

弯路

还记得上一篇随笔【IOS】将字体大小不同的文字底部对齐 么?

虽然不能够做到多个UILabel的底部对齐,但是我们可以通过继承UILabel来改变文本竖直方向的位置。

所以呢,我最初的想法是继承UILabel,可以保持其继承性, 通过NSTimer来直接慢慢移动UILable里面的文本。

这里出现了两个问题:(以@"这是自定义跑马灯里面要移动的文本"为例)

1.移动是可以移动,但是在文本左移至快要看不见(只剩下"移动的文本")的时候, 如何让@"这是.."开始从右侧出现呢?

2.文本过长的时候,看不见的部分将被截断,所以在移动的时候,只有部分文本了。

第一种好像没有办法,UILabel只存在一个文本的bounds, 不可能让他一部分在左边, 一部分在右边。 

第二种就因为存在默认的属性NSLineBreakMode:NSLineBreakByWordWrapping,就算不截断文本也只会变为省略号。

所以这种方法作罢。。。。

 

实现

首先要明确的是本跑马灯继承了UIView且需要两个UILabel、定时器NSTimer。

在初始化时,传入字符串数组,并计算各个字符串的自适应大小

CGRect textRect = [((NSString *)_textArray[i]) boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:kFont} context:nil];
[_textRectArray addObject:[NSValue valueWithCGRect:textRect]];

如果传入的字符串数组个数为1且自适应宽度<UIView宽度,则不会滚动。重新写一个UILabel用于显示就行了

其他情况下,就是可以滚动的, 在此实例化两个UILabel,并打开定时器了:

定时器相关:

_timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
//为什么要将定时器起放入LOOP中呢?
//如果此RunLoop正在执行一个连续性的运算,timer就会被延时出发。
//也就是说,如果你将跑马灯放入scrollview上,当滑动scrollview的时候,定时器就不会动了

//相关方法:
//[_timer setFireDate:[NSDate date]];   开始 //[_timer setFireDate:[NSDate distantFuture]]; 暂停
//取消定时器
//[_timer invalidate]; //_timer = nil;  //防止野指针

//定时器执行事件:

-(void)timerAction:(NSTimer *)timer{}

现在我们要做的  就是在每次进入该方法的时候来设置两个UILabel。

好了,现在假设传入了4个字符串@[@"这个是第0个字符串",@"这个是第1个字符串",@"这个是第2个字符串",@"这个是第3个字符串"];

只有两个Label, 不管向右滚动还是向左滚动,我们将最初显示的定为Labels[0], 后来显示的定位Labels[1]

定义一个变量,实时的存放前一个UILabel的origin.X值,从0开始

1.每次前一个UILabel暂未完全隐藏前,后一个UIlabel就已经出现 (两者间有一个固定的距离  internalWidth)

还需要根据speed的值更改Labels[0]的大小的增减来控制Labels[0]的位置(更改offsetX值)。

通过这个距离和前一个的位置则可以实时的计算后一个UILabel的位置(origin.X值)。

2.每次前一个UILabel完全隐藏时就需要重新设置一个值, 此时刻在每次前一个UILabel完全看不到后只进入一次

同时将左右两个UILabel变换一下位置。 往左滚动: A<--B,A消失后,A跑到B右边去了;   成为B<--A,B消失后,又要到A右边去。

所以只需要设置offsetX = _labels[1].frame.origin.x;//A消失后,将后面的B位置作为下一个将消失的label的位置,A变为后面一个,

                               //其位置根据B的位置实时计算出来。每次前一个消失后,如此循环的更换。

但是这样只更改了位置,文本以及大小却没有变换,见3.

3.对于只有一个文本来说,AB的内容都是一样的。但是对于传入的四个字符串而言,每次重新设置值的时候,需要更改AB内容。

同时,对于长度不等的字符串,需要根据不同的文本大小来设置相应AB的Frame。

所以需将四个字符串文本大小,文本内容在之前保存为一个数组。定义一个始终记录当前正准备消失的(前一个)UIlabel的位置:_currentIndex

在步骤1中: 从两个数组中分别获取用于显示在A.B里的文本数组:labelTextArray  frame数组:labelArray(从中取得宽和高)

每次AB位置交换的时候,需将currentIndex+1 : 即_currentIndex = (_currentIndex + 1)  % _textArray.count;以供交换后使用。

 

之后分别取得当前以及下一个的Text和frame   分别保存到长度为2的数组   以便使用

 

上面太多、太乱。。。。。。我不想看我不想看我不想看。。。。。。

这里有图: 看完上面还完全不懂的请看这个吧。

 

再次解释

<===============左移==================      

   

 

 

================右移=================>

现在只看颜

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇OC 内存管理 下一篇swift 2.2 语法 (上)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目