IOS 跑马灯示例

#import <UIKit/UIKit.h>

@protocol MarqueeControlDelegate <NSObject>

//点击跑马灯回调方法
-(void)selectTitleForIndex:(int)index andTitle:(NSString*)title;

@end


@interface MarqueeControl : UIView

//内容数组
@property(strong ,nonatomic)NSArray *titleArr;

//点击回调
@property(assign ,nonatomic)id<MarqueeControlDelegate> delegate;

//初始化方法
-(instancetype)initWithFrame:(CGRect)frame andContent:(NSArray*)titleArr;

-(void)start;

-(void)stop;

//重新加载跑马灯数据
-(void)resetMarqueeControlView:(NSArray*)titles;

@end

主要的思想就是跑马灯的内容展示在btn上,btn放入数组中,然后修改坐标X,动画中实现左移效果,当第一个btn移出视图,那么第一个btn要放到最后,数组中也是从第一个删除,加到最后

#import "MarqueeControl.h"


#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)

//字体大小
#define WORD_FONT 17
//动画时间
#define ANIMATE_TIME 0.05
//动画延时时间
#define ANIMATE_DELAY 0
//每条信息间隔距离
#define BUTTON_SPACING 20

#define BUTTON_TAG 100

@interface MarqueeControl()

//装载内容按钮数组
@property (strong ,nonatomic)NSMutableArray *titleBtnArr;
//是否在滚动
@property (assign ,nonatomic)BOOL revolve;

@end

@implementation MarqueeControl

//无数据初始化方法
-(instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initData];
    }
    return self;
}

//有数据初始化方法
-(instancetype)initWithFrame:(CGRect)frame andContent:(NSArray*)titleArr
{
    self = [super initWithFrame:frame];
    
    if (self) {
        [self initData];
        if (titleArr) {
            self.titleArr = titleArr;
            [self layoutContentView];
        }
    }
    return self;
}

//初始化滚动数据
-(void)initData{
    //这句话的意思就是说,内容是不是只在本视图展示,移出界面是否还展示
    self.clipsToBounds = YES;
    self.titleBtnArr = [[NSMutableArray alloc]init];
    self.revolve = NO;
}

//布局界面
#pragma mark -布局
-(void)layoutContentView
{
    //利用UILabel的sizeToFit方法,得到文字长度
    UILabel *tempLabel = [UILabel new];
    tempLabel.font = [UIFont boldSystemFontOfSize:WORD_FONT];
    for(int i=0;i<self.titleArr.count;i++)
    {
        NSString *title = self.titleArr[i];
        tempLabel.text = title;
        [tempLabel sizeToFit];
        
        //每一条内容都是一个button展示
        UIButton *titleBtn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 0, 0)];;
        titleBtn.titleLabel.font = [UIFont boldSystemFontOfSize:WORD_FONT];
        titleBtn.titleLabel.textAlignment = NSTextAlignmentCenter;
        titleBtn.tag = BUTTON_TAG+i;
        
        [titleBtn addTarget:self action:@selector(titleBtnClick:) forControlEvents:UIControlEventTouchUpInside];
        
        if (self.titleArr.count>0 && i > 0) {
            
            UIButton *btn = self.titleBtnArr[i-1];
            
            //btn的frame.x由前个按钮的坐标+间隔,长度由label提供
            titleBtn.frame = CGRectMake(btn.frame.origin.x+btn.frame.size.width, 0, tempLabel.frame.size.width+BUTTON_SPACING, self.frame.size.height);
            
        }else{
            如果是第一个按钮,就不需要它之前的按钮坐标判断位置了
            titleBtn.frame = CGRectMake(0, 0, tempLabel.frame.size.width+BUTTON_SPACING, self.frame.size.height);
        }
        
        [titleBtn setTitle:title forState:UIControlStateNormal];
        [titleBtn setTitleColor:UIColorFromRGB(0x333333) forState:UIControlStateNormal];
        titleBtn.titleLabel.font = [UIFont boldSystemFontOfSize:WORD_FONT];
      //添加到页面上
        [self addSubview:titleBtn];
     //添加到数组中
        [self.titleBtnArr addObject:titleBtn];
    }
}

//重新加载滚动内容
-(void)resetMarqueeControlView:(NSArray*)titles
{
    //先暂停动画
    [self stop];
   
    //删除按钮 
    for(UIButton *btn in self.titleBtnArr)
    {
        [btn removeFromSuperview];
        [btn.layer removeAllAnimations];
    }
    
    [self.titleBtnArr removeAllObjects];
    
    //重新加载数据
    if (titles) {
        self.titleArr = titles;
        [self layoutContentView];
    }

}

#pragma mark -操作跑马灯事件

//开始动画
-(void)start
{
    if (!self.revolve) {
        self.revolve = YES;
        [self startRevolve];
    }
    
}

//停止动画
-(void)stop{
    self.revolve = NO;
}


-(void)startRevolve
{

    //UIViewAnimationOptionAllowUserInteraction在动画过程中,允许点击交互
    [UIView animateWithDuration:ANIMATE_TIME delay:ANIMATE_DELAY options:UIViewAnimationOptionAllowUserInteraction|UIViewAnimationOptionCurveLinear animations:^{
        //执行动画,数组中的所有按钮frame.x坐标往左移动每次-1
        for (UIButton *btn in self.titleBtnArr) {
            CGRect frame = btn.frame;
            frame = CGRectMake(frame.origin.x-1, frame.origin.y, frame.size.width, frame.size.height);
            btn.frame = frame;
        }
        
    } completion:^(BOOL finished) {
        //取第一个按钮
        UIButton *btn = self.titleBtnArr[0];
        //取最后一个按钮
        UIButton *lastBtn = self.titleBtnArr[self.titleBtnArr.count-1];

        CGRect frame = btn.frame;
        //判断数组中的第一个按钮像左移动,是不是已经移出视图中
        if (frame.size.width + frame.origin.x<0) {
            //如果最后一个按钮x+width小于当前视图宽度
            if (lastBtn.frame.origin.x+lastBtn.frame.size.width<self.frame.size.width) {
                //第一个按钮的坐标要放到视图的最右边,然后慢慢左移滑入
                frame = CGRectMake(self.frame.size.width, frame.origin.y, frame.size.width, frame.size.height);
            }else{
                //第一个按钮的坐标排在最后一个按钮的后面,慢慢左移滑入
                frame = CGRectMake(lastBtn.frame.origin.x+lastBtn.frame.size.width, frame.origin.y, frame.size.width, frame.size.height);
            }
            //数组中删除第一个按钮
            [self.titleBtnArr removeObjectAtIndex:0];
            btn.frame = frame;
            //按钮加到最后面,也就是说第一个按钮,左移出了界面,就要放到界面的最后
            [self.titleBtnArr addObject:btn];
        }
      //判断是否继续滚动了
        if(self.revolve){
            
            [self startRevolve];
            
        }
    }];
}

#pragma mark -代理回调
-(void)titleBtnClick:(UIButton*)sender
{
    int index =(int)sender.tag-BUTTON_TAG;
    
    [self.delegate selectTitleForIndex:index andTitle:self.titleArr[index]];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容