iOS 控件定制实用轮子工具

iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架

2017-03-10  本文已影响645人  xiaoyouPrince

前言

广告轮播图如今早已是iOS应用的标配了,似乎任何一款App的首页都会有一个广告轮播图。

本文的目的就是要将App里面的广告轮播图封装成一个独立模块,以便简化开发过程。

如果你对独立“封装一个自己的广告轮播图”感兴趣,欢迎继续读下去。

轮播图效果

轮播图示例.gif

为了从开始讲述整个动手封装轮播图的过程,我们先从简单的开始,后期我会一步步把功能封装的更加完善起来,欢迎去我的github上去下载完整代码,如果有什么问题更欢迎随时issue我。

轮播图分析

当我们做一个很独立的功能时候可能会感觉内部功能较多而感觉无从下手,下面我们就先分析一下这个轮播图主要部件。

轮播图“原料”

思路

有了小的思路,那就开始一点点做,(这里只是简单思路,做的过程中会根据遇到的问题一点点改善)

创建基本组件

先把基本的框架和布局搭建起来

Snip20170308_2.png

这一步需要添加页面控制,标识是哪个展示图片的位置

不过在加入之前,先引入一个封装思想

封装思想

到这里就出现了一个问题,我们的功能和内容在变多,如果还像刚才这个ScrollView一样直接拖过去使用的话虽然没有问题,但是想改变整个控件位置,或者给他人使用等等的情况下就会非常麻烦,需要改动太多东西。

所以我们需要将整个控件封装起来,把里面的东西放到控件内部,以降低“轮播图”和这个项目的耦合性,增加可复用性。详解请参考iOS回顾笔记(03)

我们可以从用户的角度去考虑如何使用


    用户使用应该以简单为主,这样简单设置就能用最好。至于内部实现才是我们要关心的
        
    // 1.创建banner
    XYBannerView *banner = [XYBannerView bannerView];
    
    // 2.设置banner相关属性
    banner.imagesArr = @[@"img_00",@"img_01",@"img_02",@"img_03",@"img_04"];
    banner.frame = CGRectMake(37.5, 100, 300, 150);
    
    // 3.添加到UI上
    [self.view addSubview:banner];
    

新建BannerView文件

// 要展示图片数组
@property (nonatomic, strong) NSArray *imagesArr;

// 返回一个实例的方法
+ (instancetype)bannerView;
- (void)setImagesArr:(NSArray *)imagesArr
{
    _imagesArr = imagesArr;
    
    // 创建对应的imageView添加到scrollView中去
    for (int i = 0 ; i < imagesArr.count ;i++) {

        // 根据位置index创建图片
        NSString *imageName = [NSString stringWithFormat:@"img_0%d",i];
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
        imageView.frame = CGRectMake(i * imageView.frame.size.width, 0, imageView.frame.size.width, self.scrollView.frame.size.height);

        // 添加到ScrollView上
        [self.scrollView addSubview:imageView];
    }
    
    self.scrollView.contentSize = CGSizeMake(imagesArr.count * self.scrollView.frame.size.width, 0);
    self.scrollView.pagingEnabled = YES;
    
    
    
    // 关于pageControll的设置
    self.pageControll.numberOfPages = imagesArr.count;
    self.pageControll.currentPage = 1;
    self.pageControll.currentPageIndicatorTintColor = [UIColor yellowColor];
    self.pageControll.pageIndicatorTintColor = [UIColor grayColor];
}

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // 实时监听当前第几页,根据当前偏移量来
    self.pageControll.currentPage = (int)(self.scrollView.contentOffset.x / self.scrollView.frame.size.width + 0.5);
    
}

定时器:NSTimer 就是一个可以设置定时功能的系统组件。


// 创建定时器,设置每1.5秒进行 跳转下一页的功能
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        
        [self nextPage];
        
    }];

// 启动定时器    
[self.timer fire];

[self nextPage]方法的具体实现


    // 获取当前页数
    NSInteger page = self.pageControll.currentPage + 1;
    if (page == self.pageControll.numberOfPages) {
        page = 0;
    }
    
    // 设置滚动动画
    [UIView animateWithDuration:0.5 animations:^{
        //每次滚动就是,改变对应偏移量
        CGPoint offsize = self.scrollView.contentOffset;
        offsize.x =  page * self.scrollView.frame.size.width;
        self.scrollView.contentOffset = offsize;
    }];

到这里一个简单的广告轮播就做完了

未完善轮播图.gif

这个小轮播图马马虎虎也可以用了,但是还存在着一些严重的问题,下面来解决问题。

存在的问题

问题的解决


 #pragma mark - 重写set方法
- (void)setImagesArr:(NSArray *)imagesArr
{
    _imagesArr = imagesArr;

    // 设置内容
    [self setupContent];
    
    // 设置
    self.pageControll.numberOfPages = imagesArr.count;
    self.pageControll.currentPage = 0;
    
    
    // 设置定时功能
    [self startTimer];
    
}

- (void)setupContent
{
    // 设置图片,页码(这是一个循环,自己演算一下即可)
    for (int i = 0; i < self.scrollView.subviews.count; i++) {
        UIImageView *imageView = self.scrollView.subviews[i];
        NSInteger index = self.pageControll.currentPage;
        if (i == 0) {
            index--;
        } else if (i == 2) {
            index++;
        }
        if (index < 0) {
            index = self.pageControll.numberOfPages - 1;
        } else if (index >= self.pageControll.numberOfPages) {
            index = 0;
        }
        imageView.tag = index;
        imageView.image = [UIImage imageNamed:self.imagesArr[index]];
    }
    
    // 设置当前偏移量
    self.scrollView.contentOffset = CGPointMake(self.scrollView.frame.size.width, 0);

}


#pragma mark - 代理监听页面滚动
// 滚动的时候定位当前正确的页数
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    
    // 找出最中间的那个图片控件
    NSInteger page = 0;
    CGFloat minDistance = MAXFLOAT;
    for (int i = 0; i<self.scrollView.subviews.count; i++) {
        UIImageView *imageView = self.scrollView.subviews[i];
        CGFloat distance = 0;

            distance = ABS(imageView.frame.origin.x - scrollView.contentOffset.x);
        
        if (distance < minDistance) {
            minDistance = distance;
            page = imageView.tag;
        }
    }
    
    self.pageControll.currentPage = page;
    
}


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self setupContent];
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
    [self setupContent];
}

// 添加定时器
- (void)startTimer
{
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        
        [self nextPage];
        
    }];
    
    // 设置timer在运行循环中模式为
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    
}


// 开始滚动的时候停止定时器
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self endTimer];
}

//滚动停止的时候开启定时器
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    [self startTimer];
}

到此完美的解决了上述两个问题,如果项目需求不是很复杂,这个已经完全够用了。

小结

广告轮播的Demo基本做完了,并且修复和完善了性能和体验上的问题。

简单项目中已经基本可用了。具体使用方法


    导入框架后:

    // 1.创建banner
    XYBannerView *banner = [XYBannerView bannerView];
    
    // 2.设置banner相关属性
    banner.imagesArr = @[@"img_00",@"img_01",@"img_02",@"img_03",@"img_04"];
    banner.frame = CGRectMake(37.5, 100, 300, 150);
    
    
    // 3.添加到UI上
    [self.view addSubview:banner];
    

这个小框架还是很薄弱。并没有开放足够的接口给用户使用,这些也是后面需要一点点完善的,如果有兴趣,可以把你的意见和建议告诉我,这个小框架我会逐步完善。如果喜欢欢迎去我的github上下载源码,一起交流。

上一篇下一篇

猜你喜欢

热点阅读