前言:對(duì)于banner輪播圖摔笤,相信大家都會(huì)經(jīng)常用到蹭劈。昨天下午看到自己之前用UIScrollView
定制的banner輪播圖寫的有點(diǎn)亂,就想著再封裝一個(gè)整齊一點(diǎn)能夠大眾化使用的banner輪播圖名党,于是昨晚用UICollectionView
又重新封裝了一個(gè)帝际,感覺用著還不錯(cuò),今天給大家簡(jiǎn)單介紹一下涮拗,希望能夠幫到有需要的朋友乾戏。
原理:使用UICollectionView
通過定時(shí)器不斷改變UICollectionView
的偏移量來達(dá)到輪播滾動(dòng)的效果,通過UIScrollView
的代理方法計(jì)算UICollectionView
偏移量并關(guān)聯(lián)到UIPageControl
的currentPage
屬性實(shí)現(xiàn)滾動(dòng)的同時(shí)下方UIPageControl
的currentPage
跟著做出相應(yīng)的改變三热。
下面給大家正式講解如何來封裝:
首先創(chuàng)建一個(gè)繼承于UIView
的類RHBannerView
鼓择,在RHBannerView.h
中定義外漏的屬性和方法以及用于傳值的代理方法,如下:
#import <UIKit/UIKit.h>
#import "RHBannerModel.h"
// pageControl 所在位置
typedef NS_ENUM (NSInteger, RHBannerViewPageStyle) {
RHBannerViewPageStyleLeft = 0, // 左邊
RHBannerViewPageStyleMiddle, // 中間
RHBannerViewPageStyleRight // 右邊
};
@protocol RHBannerViewDelegate;
@interface RHBannerView : UIView
// 代理
@property (nonatomic, weak) id<RHBannerViewDelegate> delegate;
// PageControl所在位置樣式 默認(rèn)靠右
@property (nonatomic, assign) RHBannerViewPageStyle pageStyle;
// PageControl未選中圓點(diǎn)顏色 默認(rèn)灰色
@property (nonatomic, strong) UIColor * pageTintColor;
// PageControl選中圓點(diǎn)顏色 默認(rèn)白色
@property (nonatomic, strong) UIColor * currentPageTintColor;
// 輪播間隔時(shí)間 默認(rèn)3秒
@property (nonatomic, assign) NSTimeInterval intervalTime;
// 定義構(gòu)造方法快速創(chuàng)建對(duì)象
- (instancetype)initWithModels:(NSArray<RHBannerModel *> *)models;
// 定義構(gòu)造方法快速創(chuàng)建對(duì)象
- (instancetype)initWithFrame:(CGRect)frame models:(NSArray<RHBannerModel *> *)models;
/**
根據(jù)model配置bannerView
@param models 存儲(chǔ)RHBannerModel對(duì)象的數(shù)組
*/
- (void)configBannerWithModels:(NSArray<RHBannerModel *> *)models;
@end
@protocol RHBannerViewDelegate <NSObject>
@optional
// 點(diǎn)擊圖片
- (void)bannerView:(RHBannerView *)bannerView didSelectAtIndex:(NSInteger)index;
@end
這里定義了一個(gè)枚舉用來設(shè)置下方UIPageControl
所在的位置就漾,定義了一個(gè)代理方法用來傳遞當(dāng)前點(diǎn)擊的banner圖是哪一個(gè)呐能,還定制了一個(gè)RHBannerModel
來存儲(chǔ)banner圖的信息,這個(gè)model
大家可以根據(jù)自己的需求做出相應(yīng)的改動(dòng)抑堡。
外漏的方法中有兩個(gè)是定制的初始化構(gòu)造方法摆出,可以直接傳入banner模型信息的數(shù)組,不需要再次調(diào)用配置banner模型信息的對(duì)象方法首妖;如果初始化方法使用了沒有傳入banner模型信息的init
或者initWithFrame
偎漫,那么后邊需要調(diào)用配置banner模型信息的對(duì)象方法configBannerWithModels
。
下面我們來看看在RHBannerView.m
里邊的實(shí)現(xiàn)如下:
#import "RHBannerView.h"
#import "RHBannerCell.h"
#define Cell_Collection @"Cell_Collection"
@interface RHBannerView () <UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@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<RHBannerModel *> *)models {
self = [super init];
if (self) {
[self configBannerWithModels:models];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame models:(NSArray<RHBannerModel *> *)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<RHBannerModel *> *)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
這里主要就是UICollectionView
和UIPageControl
的布局實(shí)現(xiàn)有缆,在UICollectionView
的點(diǎn)擊代理方法中進(jìn)行RHBannerView
的代理回調(diào)象踊。RHBannerCell
只有一個(gè)UIImageView
來放banner圖片,其中使用到了第三方庫(kù)SDWebImage
妒貌,有需求的朋友可以進(jìn)行修改通危。
OK!到這里封裝就結(jié)束了灌曙,我們來看一下如何使用:
#import "ViewController.h"
#import "RHBannerView.h"
@interface ViewController () <RHBannerViewDelegate>
@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(@"點(diǎn)擊了上邊bannerView第%@個(gè)圖片", @(index));
} else {
NSLog(@"點(diǎn)擊了下邊bannerView2第%@個(gè)圖片", @(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
大家可以看到使用起來無論是初始化創(chuàng)建的時(shí)候添加約束傳入banner圖片信息菊碟,還是后期添加約束傳入banner圖片信息都非常簡(jiǎn)單。下面給大家呈現(xiàn)一下效果圖如下:
對(duì)了在刺,demo已經(jīng)上傳到git上邊逆害,有需要的朋友可以前往下載查看头镊,下載地址為:https://github.com/guorenhao/RHBannerView.git
最后還是希望能夠幫助到有需要的猿友們,希望我們能夠共同成長(zhǎng)進(jìn)步魄幕,愿我們能夠在開發(fā)的道路上越走越遠(yuǎn)相艇!謝謝!