iOS廣告Banner,使用三個(gè)ImgView無(wú)限循環(huán)輪播
圖片加載使用 SDWebImage 第三方庫(kù)。
WTCycleRollView.h
#import
@interface WTCycleRollView : UIView
@property (nonatomic, assign) NSTimeInterval rollTimeInterval;
/**
返回 WTCycleRollView 對(duì)象
@param frame 位置尺寸
@return WTCycleRollView 對(duì)象
*/
+ (instancetype)cycleRollViewWithFrame:(CGRect)frame;
/**
設(shè)置圖片源、是否自動(dòng)滾動(dòng)、點(diǎn)擊圖片的回調(diào)
@param imgUrls 圖片源
@param autoCycleRoll 是否自動(dòng)滾動(dòng)
@param clickImgBlock 點(diǎn)擊圖片的回調(diào)
*/
- (void)setImgUrls:(NSArray *)imgUrls autoCycleRoll:(BOOL)autoCycleRoll clickImgBlock:(void(^)(NSInteger selectedIndex))clickImgBlock;
/** 暫停自動(dòng)滾動(dòng) */
- (void)pauseCycleRoll;
/** 開(kāi)始自動(dòng)滾動(dòng)【在暫停的狀態(tài)下】 */
- (void)startCycleRoll;
@end
WTCycleRollView.m
#import "WTCycleRollView.h"
#import "UIImageView+WebCache.h"
typedef void(^ClickImgBlock) (NSInteger);
@interface WTCycleRollView ()
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIPageControl *pageControl;
@property (nonatomic, strong) UIImageView *leftImgView;
@property (nonatomic, strong) UIImageView *middleImgView;
@property (nonatomic, strong) UIImageView *rightImgView;
/** 圖片源 */
@property (nonatomic, strong) NSArray *imgUrls;
/** 當(dāng)前顯示的圖片的 Index */
@property (nonatomic, assign) NSInteger showIndex;
/** 點(diǎn)擊圖片的回調(diào) Block */
@property (nonatomic, strong) ClickImgBlock clickImgBlock;
/** 自動(dòng)滾動(dòng)的計(jì)時(shí)器 */
@property (nonatomic, strong) NSTimer *cycleRollTimer;
/** 是否手動(dòng)滑動(dòng) */
@property (nonatomic, assign) BOOL manual;
@end
@implementation WTCycleRollView
/** 默認(rèn)循環(huán)滾動(dòng)的時(shí)間間隔(s) */
static NSTimeInterval const DefaultRollTimeInterval = 4;
#pragma mark - 懶加載
- (UIImageView *)leftImgView {
if (!_leftImgView) {
_leftImgView = [[UIImageView alloc] initWithFrame:self.bounds];
}
return _leftImgView;
}
- (UIImageView *)middleImgView {
if (!_middleImgView) {
_middleImgView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds), 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
/** 為中間正在顯示的 ImgView 添加點(diǎn)擊事件 */
UITapGestureRecognizer *tapGr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickImgView)];
[_middleImgView setUserInteractionEnabled:YES];
[_middleImgView addGestureRecognizer:tapGr];
}
return _middleImgView;
}
- (UIImageView *)rightImgView {
if (!_rightImgView) {
_rightImgView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds) * 2, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
}
return _rightImgView;
}
- (UIScrollView *)scrollView {
if (!_scrollView) {
_scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
_scrollView.delegate = self;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.pagingEnabled = YES;
}
return _scrollView;
}
- (UIPageControl *)pageControl {
if (!_pageControl) {
_pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.bounds) - 20, CGRectGetWidth(self.bounds), 20)];
_pageControl.layer.shadowOpacity = 0.3;
_pageControl.layer.shadowOffset = CGSizeMake(0, 0);
}
return _pageControl;
}
#pragma mark - 初始化
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self addSubview:self.scrollView];
[_scrollView addSubview:self.leftImgView];
[_scrollView addSubview:self.middleImgView];
[_scrollView addSubview:self.rightImgView];
[self addSubview:self.pageControl];
}
return self;
}
#pragma mark - 類方法 返回 WTCycleRollView
+ (instancetype)cycleRollViewWithFrame:(CGRect)frame {
return [[self alloc] initWithFrame:frame];
}
#pragma mark - 設(shè)置圖片顯示,自動(dòng)滾動(dòng)
- (void)setImgUrls:(NSArray *)imgUrls autoCycleRoll:(BOOL)autoCycleRoll clickImgBlock:(void (^)(NSInteger))clickImgBlock {
_clickImgBlock = clickImgBlock;
_imgUrls = imgUrls;
_pageControl.numberOfPages = [imgUrls count];
_pageControl.currentPage = 0;
if ([_imgUrls count] > 1) {
[_leftImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls lastObject]]];
[_middleImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls firstObject]]];
[_rightImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls objectAtIndex:1]]];
_scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds) * 3, 0);
[_scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.bounds), 0)];
if (autoCycleRoll) {
[self stopTimer];
_cycleRollTimer = [NSTimer scheduledTimerWithTimeInterval:DefaultRollTimeInterval target:self selector:@selector(cycleRoll) userInfo:nil repeats:YES];
} else {
[self stopTimer];
}
} else {
_scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.bounds), 0);
[_leftImgView removeFromSuperview];
[_rightImgView removeFromSuperview];
if ([imgUrls count]) {
[_middleImgView sd_setImageWithURL:[NSURL URLWithString:[imgUrls firstObject]]];
_middleImgView.frame = self.bounds;
}
}
}
#pragma mark - 自動(dòng)滾動(dòng)的事件
- (void)cycleRoll {
// 當(dāng)手動(dòng)滾動(dòng)的時(shí)候,跳過(guò)此次循環(huán)
if (_manual) {
_manual = NO;
} else {
[_scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.bounds) * 2, 0) animated:YES];
}
}
- (void)clickImgView {
!_clickImgBlock ? : _clickImgBlock(_showIndex);
}
#pragma mark - UIScrollView Delegate
/** ScrollView 滑動(dòng)減速停止回調(diào)【這里根據(jù) ScrollView 的偏移量來(lái)判斷是向左滑還是向右滑】 */
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if ([_imgUrls count]) {
CGFloat offsetX = scrollView.contentOffset.x;
if (offsetX <= 0) {
// 向右滑,即將顯示上一張圖片(若當(dāng)前顯示的是第一張,則上一張為最后一張)
self.showIndex = (_showIndex + [_imgUrls count] - 1) % [_imgUrls count];
} else if (offsetX >= CGRectGetWidth(self.bounds) * 2) {
// 向右滑,即將顯示下一張圖片(若當(dāng)前顯示的是最后一張,則下一張為第一張)
self.showIndex = (_showIndex + 1) % [_imgUrls count];
}
}
}
/** 自動(dòng)滑動(dòng)【即代碼設(shè)置的滾動(dòng)(setContentOffset:animated:)】,不會(huì)直接調(diào)用上述方法(滑動(dòng)減速停止回調(diào)),但會(huì)調(diào)用此方法,在此方法再調(diào)用上述方法便可 */
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
[self scrollViewDidEndDecelerating:_scrollView];
}
/** 手動(dòng)滑動(dòng)手指觸摸屏幕的回調(diào),暫停計(jì)時(shí)器 */
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self pauseCycleRoll];
}
/** 手動(dòng)滑動(dòng)手指離開(kāi)屏幕的回調(diào),開(kāi)啟計(jì)時(shí)器 */
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
_manual = YES; // 這里開(kāi)啟計(jì)時(shí)器會(huì)立即調(diào)用循環(huán)滾動(dòng)的方法,用戶體驗(yàn)不好,所以設(shè)置此參數(shù),讓其跳過(guò)這次循環(huán)滾動(dòng)事件
[self startCycleRoll];
}
/** 根據(jù) ScrollView 偏移量設(shè)置 PageControl 的當(dāng)前頁(yè) */
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if ([_imgUrls count]) {
CGFloat offsetX = scrollView.contentOffset.x;
if (offsetX <= CGRectGetWidth(self.bounds) * 0.5) {
_pageControl.currentPage = (_showIndex + [_imgUrls count] - 1) % [_imgUrls count];
} else if (offsetX >= CGRectGetWidth(self.bounds) * 1.5) {
_pageControl.currentPage = (_showIndex + 1) % [_imgUrls count];
} else {
_pageControl.currentPage = _showIndex;
}
}
}
#pragma mark - 設(shè)置當(dāng)前顯示的圖片
- (void)setShowIndex:(NSInteger)showIndex {
_showIndex = showIndex;
// 不管向左滑還是向右滑,這里立即將將要顯示的圖片展示在中間的 ImgView 上,然后馬上將 ScrollView 偏移量設(shè)置到顯示中間的 ImgView
// 由于代碼執(zhí)行及屏幕顯示渲染非常快,肉眼幾乎看不出,所以這樣就達(dá)到了效果
[_leftImgView sd_setImageWithURL:[NSURL URLWithString:_imgUrls[(_showIndex + [_imgUrls count] - 1) % [_imgUrls count]]]];
[_middleImgView sd_setImageWithURL:[NSURL URLWithString:_imgUrls[showIndex]]];
[_rightImgView sd_setImageWithURL:[NSURL URLWithString:_imgUrls[(showIndex + 1) % [_imgUrls count]]]];
// 切記,這里設(shè)置 ScrollView 偏移量不能用動(dòng)畫(huà)
[_scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.bounds), 0)];
}
#pragma mark - 自動(dòng)滾動(dòng)時(shí),計(jì)時(shí)器的暫停與啟動(dòng)
/** 暫停計(jì)時(shí)器 */
- (void)pauseCycleRoll {
if (_cycleRollTimer) {
[_cycleRollTimer setFireDate:[NSDate distantFuture]];
}
}
/** 啟動(dòng)定時(shí)器【在計(jì)時(shí)器暫停狀態(tài)下】 */
- (void)startCycleRoll {
if (_cycleRollTimer) {
[_cycleRollTimer setFireDate:[NSDate distantPast]];
}
}
#pragma mark - 停止計(jì)時(shí)器,并釋放
- (void)stopTimer {
if (_cycleRollTimer) {
[_cycleRollTimer invalidate];
_cycleRollTimer = nil;
}
}
#pragma mark - WTCycleRollView 釋放的時(shí)候 停止計(jì)時(shí)器,并釋放,否則會(huì)造成內(nèi)存泄漏
- (void)dealloc {
[self stopTimer];
}
@end