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

//
// 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