You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
13 KiB
330 lines
13 KiB
// |
|
// KJBannerView.m |
|
// KJBannerView |
|
// |
|
// Created by 杨科军 on 2018/2/27. |
|
// Copyright © 2018年 杨科军. All rights reserved. |
|
// |
|
|
|
#import "KJBannerView.h" |
|
#import "KJBannerViewFlowLayout.h" |
|
|
|
@interface KJBannerView()<UICollectionViewDataSource,UICollectionViewDelegate> |
|
@property (nonatomic,strong) KJBannerViewFlowLayout *layout; |
|
@property (nonatomic,strong) UICollectionView *collectionView; |
|
@property (nonatomic,strong) NSTimer *timer; |
|
@property (nonatomic,strong) KJPageView *pageControl; |
|
@property (nonatomic,assign) NSUInteger nums; |
|
@property (nonatomic,assign) NSUInteger dragIndex; |
|
@property (nonatomic,assign) CGFloat lastX; |
|
@property (nonatomic,assign) BOOL useCustomCell;/// 是否自定义Cell,默认NO |
|
@property (nonatomic,assign) BOOL useDataSource;/// 是否使用KJBannerViewDataSource委托方式 |
|
|
|
@end |
|
|
|
@implementation KJBannerView |
|
/// 设置默认参数 |
|
- (void)kConfig{ |
|
_infiniteLoop = YES; |
|
_autoScroll = YES; |
|
_isZoom = NO; |
|
_itemWidth = self.bounds.size.width; |
|
_itemSpace = 0; |
|
_imgCornerRadius = 0; |
|
_autoScrollTimeInterval = 2; |
|
_bannerImageViewContentMode = UIViewContentModeScaleAspectFill; |
|
_rollType = KJBannerViewRollDirectionTypeRightToLeft; |
|
_imageType = KJBannerViewImageTypeNetIamge; |
|
_placeholderImage = [UIImage imageNamed:@"home_banner"]; |
|
_useCustomCell = NO; |
|
_kj_scale = NO; |
|
_useDataSource = NO; |
|
self.itemClass = [KJBannerViewCell class]; |
|
} |
|
- (instancetype)initWithCoder:(NSCoder*)aDecoder{ |
|
if (self = [super initWithCoder:aDecoder]) { |
|
[self kConfig]; |
|
[self addSubview:self.collectionView]; |
|
[self addSubview:self.pageControl]; |
|
} |
|
return self; |
|
} |
|
- (instancetype)initWithFrame:(CGRect)frame{ |
|
if(self = [super initWithFrame:frame]){ |
|
[self kConfig]; |
|
[self addSubview:self.collectionView]; |
|
[self addSubview:self.pageControl]; |
|
} |
|
return self; |
|
} |
|
- (void)willMoveToSuperview:(UIView*)newSuperview{ |
|
[super willMoveToSuperview:newSuperview]; |
|
[self invalidateTimer]; |
|
} |
|
#pragma mark - public |
|
/// 暂停计时器滚动处理 |
|
- (void)kj_pauseTimer{ |
|
if (_timer) { |
|
[_timer setFireDate:[NSDate distantFuture]]; |
|
} |
|
} |
|
/// 继续计时器滚动 |
|
- (void)kj_repauseTimer{ |
|
if (_timer) { |
|
[_timer setFireDate:[NSDate date]]; |
|
} |
|
} |
|
#pragma mark - setter/getter |
|
- (void)setDelegate:(id<KJBannerViewDelegate>)delegate{ |
|
_delegate = delegate; |
|
if ([delegate respondsToSelector:@selector(kj_BannerView:CurrentIndex:)]) { |
|
BOOL close = [delegate kj_BannerView:self CurrentIndex:0]; |
|
if (close) [self.pageControl removeFromSuperview]; |
|
} |
|
} |
|
- (void)setDataSource:(id<KJBannerViewDataSource>)dataSource{ |
|
_dataSource = dataSource; |
|
self.useDataSource = YES; |
|
} |
|
- (void)setImageDatas:(NSArray*)imageDatas{ |
|
_imageDatas = imageDatas; |
|
if (self.useCustomCell == NO && self.useDataSource == NO) { |
|
__weak typeof(self) weakself = self; |
|
dispatch_async(dispatch_get_global_queue(0, 0), ^{ |
|
NSMutableArray *temp = [NSMutableArray array]; |
|
for (NSString *string in imageDatas) { |
|
KJBannerDatasInfo *info = [[KJBannerDatasInfo alloc]init]; |
|
info.superType = weakself.imageType; |
|
dispatch_async(dispatch_get_global_queue(0, 0), ^{ |
|
info.imageUrl = string; |
|
}); |
|
[temp addObject:info]; |
|
} |
|
[KJBannerTool sharedInstance].imageTemps = temp.mutableCopy; |
|
temp = nil; |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
[weakself kj_dealImageDatas:imageDatas]; |
|
}); |
|
}); |
|
}else{ |
|
[self kj_dealImageDatas:imageDatas]; |
|
} |
|
} |
|
- (void)setItemClass:(Class)itemClass{ |
|
_itemClass = itemClass; |
|
if (![NSStringFromClass(itemClass) isEqualToString:@"KJBannerViewCell"]) { |
|
_useCustomCell = YES; |
|
} |
|
[self.collectionView registerClass:_itemClass forCellWithReuseIdentifier:@"KJBannerViewCell"]; |
|
} |
|
- (void)setItemWidth:(CGFloat)itemWidth{ |
|
_itemWidth = itemWidth; |
|
self.layout.itemSize = CGSizeMake(itemWidth, self.bounds.size.height); |
|
} |
|
- (void)setItemSpace:(CGFloat)itemSpace{ |
|
_itemSpace = itemSpace; |
|
self.layout.minimumLineSpacing = itemSpace; |
|
} |
|
- (void)setIsZoom:(BOOL)isZoom{ |
|
_isZoom = isZoom; |
|
self.layout.isZoom = isZoom; |
|
} |
|
- (void)setAutoScroll:(BOOL)autoScroll{ |
|
_autoScroll = autoScroll; |
|
[self invalidateTimer]; |
|
if (_autoScroll) [self setupTimer]; |
|
} |
|
|
|
#pragma mark - private |
|
/// 处理数据的相关操作 |
|
- (void)kj_dealImageDatas:(NSArray*)imageDatas{ |
|
if(imageDatas.count > 1){ |
|
_nums = self.infiniteLoop ? imageDatas.count * 10000 : imageDatas.count; |
|
self.pageControl.hidden = NO; |
|
self.collectionView.scrollEnabled = YES; |
|
[self setAutoScroll:self.autoScroll]; |
|
self.pageControl.totalPages = imageDatas.count; |
|
}else{ |
|
_nums = 100; |
|
self.pageControl.hidden = YES; |
|
self.collectionView.scrollEnabled = NO; |
|
[self invalidateTimer]; |
|
} |
|
[self.collectionView reloadData]; |
|
[self kSetCollectionItemIndexPlace]; |
|
} |
|
/// 设置初始滚动位置 |
|
- (void)kSetCollectionItemIndexPlace{ |
|
self.collectionView.frame = self.bounds; |
|
self.layout.itemSize = CGSizeMake(self.itemWidth, self.bounds.size.height); |
|
self.layout.minimumLineSpacing = self.itemSpace; |
|
if(self.collectionView.contentOffset.x == 0 && _nums > 0) { |
|
NSInteger targeIndex = self.infiniteLoop ? _nums * 0.5 : 0; |
|
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:targeIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; |
|
self.lastX = self.collectionView.contentOffset.x; |
|
self.collectionView.userInteractionEnabled = YES; |
|
} |
|
} |
|
/// 开启计时器 |
|
- (void)setupTimer{ |
|
[self invalidateTimer]; // 创建定时器前先停止定时器,不然会出现僵尸定时器,导致轮播频率错误 |
|
__weak typeof(self) weakself = self; |
|
self.timer = [NSTimer kj_scheduledTimerWithTimeInterval:self.autoScrollTimeInterval Repeats:YES Block:^(NSTimer *timer) { |
|
[weakself automaticScroll]; |
|
}]; |
|
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; |
|
} |
|
/// 释放计时器 |
|
- (void)invalidateTimer{ |
|
[_timer invalidate]; |
|
_timer = nil; |
|
} |
|
/// 自动滚动 |
|
- (void)automaticScroll{ |
|
if(_nums == 0) return; |
|
NSInteger currentIndex = [self currentIndex]; |
|
NSInteger targetIndex; |
|
if (_rollType == KJBannerViewRollDirectionTypeRightToLeft) { |
|
targetIndex = currentIndex + 1; |
|
}else{ |
|
if (currentIndex == 0) currentIndex = _nums; |
|
targetIndex = currentIndex - 1; |
|
} |
|
[self scrollToIndex:targetIndex]; |
|
} |
|
/// 当前位置 |
|
- (NSInteger)currentIndex{ |
|
if(self.collectionView.frame.size.width == 0 || self.collectionView.frame.size.height == 0) return 0; |
|
NSInteger index = 0; |
|
if (_layout.scrollDirection == UICollectionViewScrollDirectionHorizontal) {//水平滑动 |
|
index = (self.collectionView.contentOffset.x + (self.itemWidth + self.itemSpace) * 0.5) / (self.itemSpace + self.itemWidth); |
|
}else{ |
|
index = (self.collectionView.contentOffset.y + _layout.itemSize.height * 0.5) / _layout.itemSize.height; |
|
} |
|
return MAX(0,index); |
|
} |
|
/// 滚动到指定位置 |
|
- (void)scrollToIndex:(NSInteger)index{ |
|
NSInteger idx = index % _imageDatas.count; |
|
if ([self.delegate respondsToSelector:@selector(kj_BannerView:CurrentIndex:)]) { |
|
[self.delegate kj_BannerView:self CurrentIndex:idx]; |
|
} |
|
if (self.kScrollBlock) self.kScrollBlock(self,idx); |
|
if(index >= _nums){ //滑到最后则调到中间 |
|
if(self.infiniteLoop){ |
|
index = _nums * 0.5; |
|
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; |
|
} |
|
return; |
|
} |
|
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES]; |
|
} |
|
|
|
#pragma mark - UIScrollViewDelegate |
|
- (void)scrollViewDidScroll:(UIScrollView*)scrollView{ |
|
self.collectionView.userInteractionEnabled = NO; |
|
if (!self.imageDatas.count) return; |
|
self.pageControl.currentIndex = [self currentIndex] % self.imageDatas.count; |
|
} |
|
- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView{ |
|
_lastX = scrollView.contentOffset.x; |
|
if (self.autoScroll) return [self invalidateTimer]; |
|
} |
|
- (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)decelerate{ |
|
if (self.autoScroll) return [self setupTimer]; |
|
} |
|
- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView{ |
|
[self scrollViewDidEndScrollingAnimation:self.collectionView]; |
|
} |
|
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView*)scrollView{ |
|
self.collectionView.userInteractionEnabled = YES; |
|
if (!self.imageDatas.count) return; |
|
} |
|
/// 手离开屏幕的时候 |
|
- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{ |
|
CGFloat currentX = scrollView.contentOffset.x; |
|
CGFloat moveWidth = currentX - self.lastX; |
|
NSInteger shouldPage = moveWidth / (self.itemWidth*.5); |
|
if (velocity.x > 0 || shouldPage > 0) { |
|
_dragIndex = 1; |
|
}else if (velocity.x < 0 || shouldPage < 0){ |
|
_dragIndex = -1; |
|
}else{ |
|
_dragIndex = 0; |
|
} |
|
self.collectionView.userInteractionEnabled = NO; |
|
NSInteger idx = (_lastX + (self.itemWidth + self.itemSpace) * 0.5) / (self.itemSpace + self.itemWidth); |
|
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:idx + _dragIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES]; |
|
} |
|
/// 松开手指滑动开始减速的时候设置滑动动画 |
|
- (void)scrollViewWillBeginDecelerating:(UIScrollView*)scrollView{ |
|
NSInteger idx = (_lastX + (self.itemWidth + self.itemSpace) * 0.5) / (self.itemSpace + self.itemWidth); |
|
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:idx + _dragIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES]; |
|
} |
|
|
|
#pragma mark - UICollectionViewDataSource |
|
- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section{ |
|
return self.nums; |
|
} |
|
- (__kindof UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath{ |
|
KJBannerViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"KJBannerViewCell" forIndexPath:indexPath]; |
|
NSInteger itemIndex = indexPath.item % self.imageDatas.count; |
|
if (self.useDataSource) { |
|
cell.itemView = [_dataSource kj_BannerView:self BannerViewCell:cell ImageDatas:self.imageDatas Index:itemIndex]; |
|
return cell; |
|
}else if (self.useCustomCell) { |
|
cell.model = self.imageDatas[itemIndex]; |
|
return cell; |
|
}else { /// 自带Cell处理 |
|
cell.kj_scale = self.kj_scale; |
|
cell.imgCornerRadius = self.imgCornerRadius; |
|
cell.placeholderImage = self.placeholderImage; |
|
cell.contentMode = self.bannerImageViewContentMode; |
|
cell.info = [KJBannerTool sharedInstance].imageTemps[itemIndex]; |
|
return cell; |
|
} |
|
} |
|
|
|
#pragma mark - UICollectionViewDelegate |
|
- (void)collectionView:(UICollectionView*)collectionView didSelectItemAtIndexPath:(NSIndexPath*)indexPath{ |
|
NSInteger idx = [self currentIndex] % self.imageDatas.count; |
|
if ([self.delegate respondsToSelector:@selector(kj_BannerView:SelectIndex:)]) { |
|
[self.delegate kj_BannerView:self SelectIndex:idx]; |
|
} |
|
if (self.kSelectBlock) { |
|
self.kSelectBlock(self,idx); |
|
} |
|
} |
|
|
|
#pragma mark - lazy |
|
- (KJBannerViewFlowLayout*)layout{ |
|
if(!_layout){ |
|
_layout = [[KJBannerViewFlowLayout alloc]init]; |
|
_layout.isZoom = self.isZoom; |
|
_layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; |
|
_layout.minimumLineSpacing = 0; |
|
} |
|
return _layout; |
|
} |
|
- (UICollectionView*)collectionView{ |
|
if(!_collectionView){ |
|
_collectionView = [[UICollectionView alloc]initWithFrame:self.bounds collectionViewLayout:self.layout]; |
|
_collectionView.delegate = self; |
|
_collectionView.dataSource = self; |
|
_collectionView.scrollsToTop = NO; |
|
_collectionView.showsVerticalScrollIndicator = NO; |
|
_collectionView.showsHorizontalScrollIndicator = NO; |
|
_collectionView.backgroundColor = self.backgroundColor; |
|
} |
|
return _collectionView; |
|
} |
|
- (KJPageView*)pageControl{ |
|
if(!_pageControl){ |
|
_pageControl = [[KJPageView alloc]initWithFrame:CGRectMake(0, self.bounds.size.height - 15, self.bounds.size.width, 15)]; |
|
} |
|
return _pageControl; |
|
} |
|
|
|
@end |
|
|
|
|
|
|