iOS开发-自定制banner轮播图

iOS开发-自定制banner轮播图_第1张图片
banner.png

前言:对于banner轮播图,相信大家都会经常用到。昨天下午看到自己之前用UIScrollView定制的banner轮播图写的有点乱,就想着再封装一个整齐一点能够大众化使用的banner轮播图,于是昨晚用UICollectionView又重新封装了一个,感觉用着还不错,今天给大家简单介绍一下,希望能够帮到有需要的朋友。

原理:使用UICollectionView通过定时器不断改变UICollectionView的偏移量来达到轮播滚动的效果,通过UIScrollView的代理方法计算UICollectionView偏移量并关联到UIPageControlcurrentPage属性实现滚动的同时下方UIPageControlcurrentPage跟着做出相应的改变。

下面给大家正式讲解如何来封装:
首先创建一个继承于UIView的类RHBannerView,在RHBannerView.h中定义外漏的属性和方法以及用于传值的代理方法,如下:

#import 
#import "RHBannerModel.h"

// pageControl 所在位置
typedef NS_ENUM (NSInteger, RHBannerViewPageStyle) {
    
    RHBannerViewPageStyleLeft = 0,  // 左边
    RHBannerViewPageStyleMiddle,    // 中间
    RHBannerViewPageStyleRight      // 右边
};

@protocol RHBannerViewDelegate;
@interface RHBannerView : UIView
// 代理
@property (nonatomic, weak) id delegate;
// PageControl所在位置样式  默认靠右
@property (nonatomic, assign) RHBannerViewPageStyle pageStyle;
// PageControl未选中圆点颜色 默认灰色
@property (nonatomic, strong) UIColor * pageTintColor;
// PageControl选中圆点颜色  默认白色
@property (nonatomic, strong) UIColor * currentPageTintColor;
// 轮播间隔时间  默认3秒
@property (nonatomic, assign) NSTimeInterval intervalTime;

// 定义构造方法快速创建对象
- (instancetype)initWithModels:(NSArray *)models;
// 定义构造方法快速创建对象
- (instancetype)initWithFrame:(CGRect)frame models:(NSArray *)models;

/**
 根据model配置bannerView

 @param models 存储RHBannerModel对象的数组
 */
- (void)configBannerWithModels:(NSArray *)models;

@end
@protocol RHBannerViewDelegate 

@optional
// 点击图片
- (void)bannerView:(RHBannerView *)bannerView didSelectAtIndex:(NSInteger)index;

@end

这里定义了一个枚举用来设置下方UIPageControl所在的位置,定义了一个代理方法用来传递当前点击的banner图是哪一个,还定制了一个RHBannerModel来存储banner图的信息,这个model大家可以根据自己的需求做出相应的改动。

外漏的方法中有两个是定制的初始化构造方法,可以直接传入banner模型信息的数组,不需要再次调用配置banner模型信息的对象方法;如果初始化方法使用了没有传入banner模型信息的init或者initWithFrame,那么后边需要调用配置banner模型信息的对象方法configBannerWithModels

下面我们来看看在RHBannerView.m里边的实现如下:

#import "RHBannerView.h"
#import "RHBannerCell.h"

#define Cell_Collection    @"Cell_Collection"
@interface RHBannerView () 

@property (nonatomic, strong) UICollectionView * collection;
@property (nonatomic, strong) UIPageControl * pageControl;
@property (nonatomic, strong) NSTimer * timer;

@property (nonatomic, strong) NSMutableArray * dataArr;

@property (nonatomic, assign) NSInteger page;
@end
@implementation RHBannerView

- (instancetype)initWithFrame:(CGRect)frame {
    
    self = [super initWithFrame:frame];
    
    if (self) {
        
        _page = 1;
        _intervalTime = 3;
        [self addSubviews];
        self.pageStyle = RHBannerViewPageStyleRight;
        self.backgroundColor = [UIColor yellowColor];
    }
    return self;
}

- (instancetype)initWithModels:(NSArray *)models {
    
    self = [super init];
    
    if (self) {
        
        [self configBannerWithModels:models];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame models:(NSArray *)models {
    
    self = [super initWithFrame:frame];
    
    if (self) {
        
        _page = 1;
        _intervalTime = 3;
        [self addSubviews];
        self.pageStyle = RHBannerViewPageStyleRight;
        self.backgroundColor = [UIColor yellowColor];
        [self configBannerWithModels:models];
    }
    return self;
}

- (void)addSubviews {
    
    [self addSubview:self.collection];
    [self addSubview:self.pageControl];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    _collection.frame = self.bounds;
    [self makeConstraintForPageControlWithPageStyle:self.pageStyle];
    if (self.dataArr.count > 1) {
        
        [_collection setContentOffset:CGPointMake(self.bounds.size.width, 0)];
    }
    [_collection reloadData];
}

#pragma mark - public

- (void)configBannerWithModels:(NSArray *)models {
    
    [self.dataArr removeAllObjects];
    [self removeTimer];
    _pageControl.numberOfPages = 0;
    
    if (models.count == 0) {
        
        [_collection reloadData];
        return;
    }
    
    if (models.count == 1) {
        
        [self.dataArr addObjectsFromArray:models];
    } else {
        
        [self.dataArr addObject:models.lastObject];
        [self.dataArr addObjectsFromArray:models];
        [self.dataArr addObject:models.firstObject];
        [_collection setContentOffset:CGPointMake(self.bounds.size.width, 0)];
        _pageControl.numberOfPages = models.count;
        [self makeConstraintForPageControlWithPageStyle:self.pageStyle];
        [self addTimer];
    }
    [_collection reloadData];
}

- (void)run {
    
    if (self.dataArr.count > 1) {
        
        [self addTimer];
    }
}

- (void)stop {
    
    [self removeTimer];
}

#pragma mark - private

- (void)makeConstraintForPageControlWithPageStyle:(RHBannerViewPageStyle)pageStyle {
    
    float interval = 15;
    switch (pageStyle) {
        case RHBannerViewPageStyleLeft:
            _pageControl.frame = CGRectMake(10, self.bounds.size.height - 50, self.dataArr.count * interval, 50);
            break;
        case RHBannerViewPageStyleMiddle:
            _pageControl.frame = CGRectMake((self.bounds.size.width - self.dataArr.count * interval) / 2 , self.bounds.size.height - 50, self.dataArr.count * interval, 50);
            break;
        case RHBannerViewPageStyleRight:
            _pageControl.frame = CGRectMake(self.bounds.size.width - 10 - self.dataArr.count * interval, self.bounds.size.height - 50, self.dataArr.count * interval, 50);
            break;
            
        default:
            break;
    }
}

#pragma mark - timer

- (void)addTimer {
    
    if (!self.timer) {
        
        self.timer = [NSTimer scheduledTimerWithTimeInterval:self.intervalTime target:self selector:@selector(bannerRun) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    }
}

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

- (void)bannerRun {
    
    _page++;
    [self.collection setContentOffset:CGPointMake(_page * self.bounds.size.width, 0) animated:YES];
    
    if (_page == self.dataArr.count - 1) {
        
        _page = 1;
    }
}

#pragma mark - collectionView delegate and dataSource

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    
    return self.dataArr.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    RHBannerCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:Cell_Collection forIndexPath:indexPath];
    if (indexPath.row < self.dataArr.count) {
        
        RHBannerModel * model = self.dataArr[indexPath.row];
        [cell configCellWithImageUrl:model.picture placeholderImage:[UIImage imageNamed:model.placeholderName]];
    }
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    
    NSInteger index = indexPath.row;
    if (index == 0) {
        
        index = self.dataArr.count - 3;
    } else if (index == self.dataArr.count - 1) {
        
        index = 0;
    } else {
        
        index -= 1;
    }
    if (self.delegate && [self.delegate respondsToSelector:@selector(bannerView:didSelectAtIndex:)]) {
        
        [self.delegate bannerView:self didSelectAtIndex:index];
    }
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    return self.bounds.size;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    if (scrollView == _collection) {
        
        if (self.dataArr.count > 1) {
            
            _page = _collection.contentOffset.x / self.bounds.size.width;
            
            if (_collection.contentOffset.x == 0) {
                
                _pageControl.currentPage = self.dataArr.count - 3;
                [_collection setContentOffset:CGPointMake(self.bounds.size.width * (self.dataArr.count - 2), 0)];
            } else if (_collection.contentOffset.x == self.bounds.size.width * (self.dataArr.count - 1)) {
                
                _pageControl.currentPage = 0;
                [_collection setContentOffset:CGPointMake(self.bounds.size.width, 0)];
            } else if (_collection.contentOffset.x == self.bounds.size.width * _page) {
                
                _pageControl.currentPage = _page - 1;
            }
        }
    }
}

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

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

#pragma mark - setter and getter

- (UICollectionView *)collection {
    
    if (!_collection) {
        
        UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc] init];
        layout.minimumInteritemSpacing = 0;
        layout.minimumLineSpacing = 0;
        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        UICollectionView * collection = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
        collection.dataSource = self;
        collection.delegate = self;
        collection.bounces = NO;
        collection.pagingEnabled = YES;
        collection.showsHorizontalScrollIndicator = NO;
        collection.backgroundColor = [UIColor whiteColor];
        [collection registerClass:[RHBannerCell class] forCellWithReuseIdentifier:Cell_Collection];
        _collection = collection;
    }
    return _collection;
}

- (UIPageControl *)pageControl {
    
    if (!_pageControl) {
        
        UIPageControl * pageControl = [[UIPageControl alloc] init];
        pageControl.pageIndicatorTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.9];
        pageControl.currentPageIndicatorTintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9];
        _pageControl = pageControl;
    }
    return _pageControl;
}

- (NSMutableArray *)dataArr {
    
    if (!_dataArr) {
        
        _dataArr = [NSMutableArray array];
    }
    return _dataArr;
}

- (void)setPageStyle:(RHBannerViewPageStyle)pageStyle {
    
    _pageStyle = pageStyle;
    [self makeConstraintForPageControlWithPageStyle:pageStyle];
}

- (void)setPageTintColor:(UIColor *)pageTintColor {
    
    _pageTintColor = pageTintColor;
    self.pageControl.pageIndicatorTintColor = pageTintColor;
}

- (void)setCurrentPageTintColor:(UIColor *)currentPageTintColor {
    
    _currentPageTintColor = currentPageTintColor;
    self.pageControl.currentPageIndicatorTintColor = currentPageTintColor;
}

- (void)setIntervalTime:(NSTimeInterval)intervalTime {
    
    _intervalTime = intervalTime;
    
    if (self.dataArr.count > 0) {
        
        [self removeTimer];
        [self addTimer];
    }
}

@end

这里主要就是UICollectionViewUIPageControl的布局实现,在UICollectionView的点击代理方法中进行RHBannerView的代理回调。RHBannerCell只有一个UIImageView来放banner图片,其中使用到了第三方库SDWebImage,有需求的朋友可以进行修改。

OK!到这里封装就结束了,我们来看一下如何使用:

#import "ViewController.h"
#import "RHBannerView.h"

@interface ViewController () 

@property (nonatomic, strong) RHBannerView * bannerView;

@property (nonatomic, strong) RHBannerView * bannerView2;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.view addSubview:self.bannerView];
    [self.view addSubview:self.bannerView2];
    [self makeConstraintsForUI];
    
    RHBannerModel * model1 = [[RHBannerModel alloc] init];
    model1.placeholderName = @"001.jpg";
    RHBannerModel * model2 = [[RHBannerModel alloc] init];
    model2.placeholderName = @"002.jpg";
    RHBannerModel * model3 = [[RHBannerModel alloc] init];
    model3.placeholderName = @"003.jpg";
    RHBannerModel * model4 = [[RHBannerModel alloc] init];
    model4.placeholderName = @"004.jpg";
    RHBannerModel * model5 = [[RHBannerModel alloc] init];
    model5.placeholderName = @"005.jpg";
    [_bannerView configBannerWithModels:@[model1, model2, model3, model4, model5]];
}

- (void)makeConstraintsForUI {
    
    [_bannerView mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.left.mas_equalTo(@0);
        make.top.mas_equalTo(@0);
        make.right.mas_equalTo(@0);
        make.height.mas_equalTo(_bannerView.mas_width).multipliedBy(9/16.0);
    }];
}

#pragma mark - bannerView delegate

- (void)bannerView:(RHBannerView *)bannerView didSelectAtIndex:(NSInteger)index {
    
    if (bannerView == _bannerView) {
        
        NSLog(@"点击了上边bannerView第%@个图片", @(index));
    } else {
        
        NSLog(@"点击了下边bannerView2第%@个图片", @(index));
    }
    
}

- (RHBannerView *)bannerView {
    
    if (!_bannerView) {
        
        RHBannerView * bannerView = [[RHBannerView alloc] init];
        bannerView.pageStyle = RHBannerViewPageStyleMiddle;
        bannerView.delegate = self;
        bannerView.pageTintColor = [UIColor lightGrayColor];
        bannerView.currentPageTintColor = [UIColor redColor];
        bannerView.intervalTime = 2;
        _bannerView = bannerView;
    }
    return _bannerView;
}

- (RHBannerView *)bannerView2 {
    
    if (!_bannerView2) {
        
        RHBannerModel * model1 = [[RHBannerModel alloc] init];
        model1.placeholderName = @"001.jpg";
        RHBannerModel * model2 = [[RHBannerModel alloc] init];
        model2.placeholderName = @"002.jpg";
        RHBannerModel * model3 = [[RHBannerModel alloc] init];
        model3.placeholderName = @"003.jpg";
        RHBannerModel * model4 = [[RHBannerModel alloc] init];
        model4.placeholderName = @"004.jpg";
        RHBannerModel * model5 = [[RHBannerModel alloc] init];
        model5.placeholderName = @"005.jpg";
        RHBannerView * bannerView = [[RHBannerView alloc] initWithFrame:CGRectMake(0, 300, self.view.bounds.size.width, 200) models:@[model1, model2, model3, model4, model5]];
        bannerView.delegate = self;
        bannerView.intervalTime = 3;
        _bannerView2 = bannerView;
    }
    return _bannerView2;
}
@end

大家可以看到使用起来无论是初始化创建的时候添加约束传入banner图片信息,还是后期添加约束传入banner图片信息都非常简单。下面给大家呈现一下效果图如下:


banner.gif

对了,demo已经上传到git上边,有需要的朋友可以前往下载查看,下载地址为:https://github.com/guorenhao/RHBannerView.git

最后还是希望能够帮助到有需要的猿友们,希望我们能够共同成长进步,愿我们能够在开发的道路上越走越远!谢谢!

你可能感兴趣的:(iOS开发-自定制banner轮播图)