摆脱第三方库系列(二)- 自己写一个滚动广告

前言

摆脱第三方库系列第二章,我将介绍滚动广告的写法。在一些信息聚合类APP中滚动广告非常常见或者说必不可少,他可以不需要用户操作展示一些开发者想展示的东西,原理其实也很简单。我写的滚动广告主要实现自动滚动和循环滚动这两个功能,至于广告的点击事件或者美化这都是后话了。

滚动广告基本原理

其实只要是滚动的东西都离不开UISCrollView,滚动广告的原理就是在一个横向的UISCrollView上放置多张图片并插入文字,然后设置时间自动翻页,点击事件可以通过设置代理方法完成。

而循环播放的原理是这样的,假使我们有五张广告图需要播放,那么我们在UISCrollView应该插入七张图片,除开头尾两张后中间剩下的五张按顺序放置我们要展示的广告,那么头尾两部分放什么呢?

头部分应该放最后一张也就是第五张广告图,尾部分应该放第一张广告图

这样当用户看到第一张广告图并向左移动时就会出现第五张广告图,然后我们应该在代码中使用一些“小手段”,当广告页滚动到头页的时候应该自动跳到倒数第二页也就是第五张广告页。这样就完成了一个看起来可以循环的轮播广告了。

代码实现

先上完成效果图

wait
wait

接下来上代码,先创建一个继承于UIView的子类RollView,这里不推荐直接继承于UISCrollView,那样可能会因为控件层次问题出现有些控件被覆盖了。

接口部分

RollView接口部分如下

@interface RollView : UIView<UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *rollScrollView;
@property (nonatomic, strong) NSMutableArray *imageArray;
@property (nonatomic, strong) UIImageView *rollImgView;
@property (nonatomic, strong) UIPageControl *pageControl;
@property (nonatomic, strong) NSTimer *timer;
@end

UIPageControl是一个苹果公司给的页面小点的控件,也是滚动广告比较常见的需要添加的控件。而imageArray主要是为了存储多个广告图,可以自己封装一个UIImageView这样就可以让自己的广告更加个性了。

为了简化代码先宏定义下

#define COUNT self.imageArray.count
#define SVIEWWIDTH self.frame.size.width
#define SVIEWHEIGHT self.frame.size.height

RollView初始化

先看自身的初始化方法,很简单,addNSTimer方法是添加一个定时器滚动,一会再介绍。

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if(self){
        [self addSubview:self.rollScrollView];
        [self addSubview:self.pageControl];
        [self addNSTimer];
    }
    return self;
}

各个控件get方法

接下来看get方法

- (UIScrollView *)rollScrollView
{
    if (_rollScrollView == nil) {
        _rollScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SVIEWWIDTH, SVIEWHEIGHT)];
        _rollScrollView.delegate = self;
        _rollScrollView.contentSize = CGSizeMake((COUNT + 2) * SVIEWWIDTH, SVIEWHEIGHT);
        //使子视图imageview自动适配scrollview的大小
        [_rollScrollView setAutoresizesSubviews:YES];
        //将scrollview设成分页形式
        [_rollScrollView setPagingEnabled:YES];
        //隐藏scrollview两边的滚动条
        [_rollScrollView setShowsVerticalScrollIndicator:NO];
        [_rollScrollView setShowsHorizontalScrollIndicator:NO];
        //设置scrollview初始的位置为第二部分来显示第一张广告
        _rollScrollView.contentOffset = CGPointMake(SVIEWWIDTH, 0);
    }
    return _rollScrollView;
}

什么是UISCrollView的contentSize我在这篇文章讲过。由于要循环播放所以要加两张图片,所以宽度为(COUNT + 2) * SVIEWWIDTH,其他解释写在注释里了。

然后是pageControl的get方法。

- (UIPageControl *)pageControl
{
    if (_pageControl == nil) {
        _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake((SVIEWWIDTH - _pageControl.bounds.size.width)/2, SVIEWHEIGHT - 10, _pageControl.bounds.size.width, _pageControl.bounds.size.height)];
        _pageControl.currentPageIndicatorTintColor = [UIColor whiteColor];
        _pageControl.pageIndicatorTintColor = [UIColor grayColor];
        [_pageControl setNumberOfPages:COUNT];
    }
    return _pageControl;
}

其中currentPageIndicatorTintColor是点移动到当前点时的颜色,pageIndicatorTintColor是没移动到的点的颜色。

然后在imageArray中添加我们的广告图片,由于NSArray是可以存储任何对象类型的,所以我们可以存储广告图也可以直接存UIImageView,这里我是存了任意的五张UIImage,就不上代码了,直接看rollImgView

- (UIImageView *)rollImgView
{
    if (_rollImgView == nil) {
        //第一个放最后一个图片
        _rollImgView = [[UIImageView alloc] init];
        _rollImgView.frame = CGRectMake(0, 0, SVIEWWIDTH, SVIEWHEIGHT);
        [_rollImgView setImage:[_imageArray objectAtIndex:(COUNT - 1)]];
        [self.rollScrollView addSubview:_rollImgView];
        //最后一个放第一张图片
        _rollImgView = [[UIImageView alloc] init];
        _rollImgView.frame = CGRectMake(SVIEWWIDTH * (COUNT + 1), 0, SVIEWWIDTH, SVIEWHEIGHT);
        [_rollImgView setImage:[_imageArray objectAtIndex:0]];
        [self.rollScrollView addSubview:_rollImgView];
    
        for (int i = 0; i < COUNT; i++) {
            _rollImgView = [[UIImageView alloc] init];
            _rollImgView.frame = CGRectMake(SVIEWWIDTH * (i + 1), 0, SVIEWWIDTH, SVIEWHEIGHT);
            [_rollImgView setImage:[_imageArray objectAtIndex:i]];
            [self.rollScrollView addSubview:_rollImgView];
        }
    }
    return _rollImgView;
}

这里需要注意的就是每个图片需要放置的frame,想不明白的自己动手画个草稿就一目了然了。我是设置了五张广告图片所以我们应该用七张UIImageView,所以要初始化七次添加七次,可能有点不合理,有更好的办法希望留言告诉我。

scrollView代理部分

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView.contentOffset.x == 0) {
        self.rollScrollView.contentOffset = CGPointMake(COUNT * SVIEWWIDTH, 0);
        self.pageControl.currentPage = (COUNT - 1);
    }else if (scrollView.contentOffset.x == (COUNT + 1) * SVIEWWIDTH){
        self.rollScrollView.contentOffset = CGPointMake(SVIEWWIDTH, 0);
        self.pageControl.currentPage = 0;
    }else{
        int pagenum = (round(scrollView.contentOffset.x/self.rollImgView.frame.size.width) - 1);
        [self.pageControl setCurrentPage:pagenum];
    }
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self removeNSTimer];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    [self addNSTimer];
}

主要代码都在scrollViewDidScroll方法中,就是在scrollview滚动时调用的方法。这里主要就是前面提到的实现循环滚动的“小手段”了。

scrollView.contentOffset.x == 0时,说明的此时显示的是头imageview即第五张广告,那么我们需要跳动到第五张广告也就是第六张imageview来完成循环效果,同时也别忘记改版pageControl的当前点。由于是5个点,那么下标是0-4,所以是标到(COUNT - 1)处。

scrollView.contentOffset.x == (COUNT + 1) * SVIEWWIDTH表示的是在尾imageview时的操作。

如果既不在头也不在尾,我们只需要在滚动时改变标签点就可以了。其中round是表示取四舍五入的整数,这样改变标签点更合理。

下面两个方法是说我们鼠标按住scrollview时我们应该取消计时器不再计时,松开手时再开始计时。

计时器

- (void)addNSTimer
{
    if (self.timer == nil) {
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:4 target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
        [[NSRunLoop mainRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
        self.timer = timer;
    }
}

- (void)removeNSTimer
{
    [self.timer invalidate];
    self.timer =nil;
}

- (void)nextPage
{
    if (self.rollScrollView.contentOffset.x == ((COUNT) * self.rollImgView.frame.size.width)) {
        [self.rollScrollView scrollRectToVisible:CGRectMake(SVIEWWIDTH, 0, SVIEWWIDTH, SVIEWHEIGHT) animated:YES];
    }else{
        [self.rollScrollView scrollRectToVisible:CGRectMake(self.rollScrollView.contentOffset.x + self.rollImgView.frame.size.width, 0, SVIEWWIDTH, SVIEWHEIGHT) animated:YES];
    }
}

这里主要是三个自定义方法,顾名思义都比较简单,这里不做详细介绍了。

接下来就将RollView添加到ViewController中就可以展示了。

总结

这样滚动广告差不多就介绍完了,我只是介绍了基本原理,在我们的开发中肯定是不能完全满足需求的,所以还要加一些自定义的更改。比如用自定义的imageview并用代理方法增加点击事件,或者直接不用imageview用buttun。demo我也会放到我的github上。

还是那句话,如果有错还请指出,万分感谢。

相关文章

摆脱第三方库系列(一)-自己写一个侧拉菜单

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

推荐阅读更多精彩内容