第四十六篇、UICollectionView广告轮播控件

这是利用人的视觉错觉来实现无限轮播,UICollectionView 有很好的重用机制,这只是部分核心代码,后期还要继续完善和代码重构。

#import <UIKit/UIKit.h>
#import "ADPageControlView.h"

@interface ADCarouselView : UIView

/**图片资源数组*/
@property (nonatomic, strong) NSArray *imgs;

/**标题数组*/
@property (nonatomic, strong) NSArray *titles;

/**是否无限循环轮播*/
@property (nonatomic, assign)  BOOL loop;

/**自动轮播时间间隔,默认为0,0表示不开启自动轮播*/
@property (nonatomic, assign)  NSTimeInterval automaticallyScrollDuration;

/**图片的展开方式*/
@property (nonatomic, assign)  UIViewContentMode imageContentMode;

/**占位图片*/
@property (copy, nonatomic) NSString *placeholderImageName;

+ (instancetype)carouselViewWithFrame:(CGRect)frame;

/**分页控制(相关属性自行设置,不设置使用默认属性)*/
@property (strong, nonatomic) ADPageControlView *pageControlView;
/**标题*/
@property (nonatomic, strong) UILabel *titleLabel;

@end
#import "ADCarouselView.h"

#define kADCarouselViewLeftMargin 10

#define kPageControlViewDefaultW 80
#define kPageControlViewDefaultH 44

#define kTitleLabelToTitleLabelMargin 10

#define kTitleLabelDefaultH kPageControlViewDefaultH

#define kPageControlViewDefaultFrame CGRectMake([UIScreen mainScreen].bounds.size.width - kPageControlViewDefaultW - kADCarouselViewLeftMargin, self.bounds.size.height - kPageControlViewDefaultH, kPageControlViewDefaultW, kPageControlViewDefaultH)

#define kTitleLabelDefaultFrame CGRectMake(kADCarouselViewLeftMargin, self.bounds.size.height - kTitleLabelDefaultH, [UIScreen mainScreen].bounds.size.width - kPageControlViewDefaultW - kADCarouselViewLeftMargin - kADCarouselViewLeftMargin - kTitleLabelToTitleLabelMargin, kTitleLabelDefaultH)

#define kTitleLabelDefaultTextColor [UIColor whiteColor]
#define kTitleLabelDefaultFont [UIFont systemFontOfSize:14]

@class ADCarouselViewCell;

#pragma mark - ADCarouselViewCell(轮播图子控件)

@interface ADCarouselViewCell : UICollectionViewCell

/**图片名称*/
@property (copy, nonatomic) NSString *imgName;

@end

@interface ADCarouselViewCell()

/**图片*/
@property (weak, nonatomic) UIImageView *imgView;

@end

@implementation ADCarouselViewCell

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self setUpCarouselViewCell];
    }
    return self;
}

- (void)setUpCarouselViewCell
{
    UIImageView *imgView = [[UIImageView alloc] init];
    imgView.contentMode = UIViewContentModeCenter;
    self.imgView = imgView;
    [self.contentView addSubview:self.imgView];
    self.backgroundColor = [UIColor whiteColor];
}

- (void)setImgName:(NSString *)imgName
{
    _imgName = imgName;
    self.imgView.image = [UIImage imageNamed:_imgName];
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    self.imgView.frame = self.bounds;
}

@end

#pragma mark - ADCarouselView(轮播图控件)

@interface ADCarouselView()<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>

/**轮播控件*/
@property (weak, nonatomic) UICollectionView *carouselView;

/**布局*/
@property (nonatomic, strong) UICollectionViewFlowLayout *layout;

/**轮播图片数组*/
@property (nonatomic, strong) NSMutableArray *carouselImages;

/**自动轮播定时器*/
@property (nonatomic, strong) NSTimer *timer;

/**当前滚动的位置*/
@property (nonatomic, assign)  NSInteger currentIndex;

/**上次滚动的位置*/
@property (nonatomic, assign)  NSInteger lastIndex;

@end

@implementation ADCarouselView

+ (instancetype)carouselViewWithFrame:(CGRect)frame
{
    ADCarouselView *carouselView = [[self alloc] initWithFrame:frame];
    return carouselView;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        //1、添加collectionview
        //1.1设置collectionview布局
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        self.layout = layout;
        layout.minimumLineSpacing = 0;
        layout.minimumInteritemSpacing = 0;
        //设置滚动方向
        layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        //1.2初始化collectionview
        UICollectionView *carouselView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout];
        carouselView.showsHorizontalScrollIndicator = NO;
        carouselView.pagingEnabled = YES;
        carouselView.delegate = self;
        carouselView.dataSource = self;
        //2、注册cell类型
        [carouselView registerClass:[ADCarouselViewCell class] forCellWithReuseIdentifier:@"carouselViewCell"];
        self.carouselView = carouselView;
        //3、添加为子控件
        [self addSubview:carouselView];
        //4、设置自动滚动时间间隔
        self.loop = NO;
        self.automaticallyScrollDuration = 0;
        
        //添加标题和分页
        self.titleLabel.frame = kTitleLabelDefaultFrame;
        self.pageControlView.frame = kPageControlViewDefaultFrame;
        self.titleLabel.textColor = kTitleLabelDefaultTextColor;
        self.titleLabel.font = kTitleLabelDefaultFont;
    }
    return self;
}

#pragma mark 自动滚动时间设置

- (void)setAutomaticallyScrollDuration:(NSTimeInterval)automaticallyScrollDuration
{
    _automaticallyScrollDuration = automaticallyScrollDuration;
    if (_automaticallyScrollDuration > 0)
    {
        [self.timer invalidate];
        self.timer = nil;
        NSTimer *timer = [NSTimer timerWithTimeInterval:self.automaticallyScrollDuration target:self selector:@selector(startScrollAutomtically) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        self.timer = timer;
    }
    else
    {
        [self.timer invalidate];
    }
}

#pragma mark 构造新的图片数组

- (NSMutableArray *)carouselImages
{
    if (!_carouselImages) {
        _carouselImages = [NSMutableArray arrayWithArray:self.imgs];
        if (self.loop && self.imgs.count > 0)
        {
            [_carouselImages insertObject:[self.imgs lastObject] atIndex:0];
            [_carouselImages addObject:self.imgs[0]];
        }
    }
    return _carouselImages;
}

#pragma mark 自动滚动
- (void)startScrollAutomtically
{
    NSInteger currentIndex = self.currentIndex + 1;
    currentIndex = (currentIndex == self.carouselImages.count) ? 1 : currentIndex;
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:currentIndex inSection:0];
    BOOL isNeedAnim = self.automaticallyScrollDuration <= 0.3 ? NO : YES;
    [self.carouselView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:isNeedAnim];
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.carouselView.frame = self.bounds;
    
    //默认滚动到第一张图片
    if (self.loop && self.carouselView.contentOffset.x == 0)
    {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:0];
        [self.carouselView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
        self.currentIndex = 1;
    }
}

#pragma mark 代理方法

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    ADCarouselViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"carouselViewCell" forIndexPath:indexPath];
    cell.imgView.contentMode = self.imageContentMode;
    cell.imgName = self.carouselImages[indexPath.row];
    return cell;
}

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

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat width = self.frame.size.width;
    NSInteger index = (scrollView.contentOffset.x + width * 0.5) / width;
    if (self.loop)
    {
        //当滚动到最后一张图片时,继续滚向后动跳到第一张
        if (index == self.imgs.count + 1)
        {
            self.currentIndex = 1;
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.currentIndex inSection:0];
            [self.carouselView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
            return;
        }
        
        //当滚动到第一张图片时,继续向前滚动跳到最后一张
        if (scrollView.contentOffset.x < width * 0.5)
        {
            self.currentIndex = self.imgs.count;
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.currentIndex inSection:0];
            [self.carouselView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
            return;
        }
    }
    
    //避免多次调用currentIndex的setter方法
    if (self.currentIndex != self.lastIndex)
    {
        self.currentIndex = index;
    }
    self.lastIndex = index;
    
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    //关闭自动滚动
    [self.timer invalidate];
}

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    if (self.automaticallyScrollDuration > 0)
    {        
        [self.timer invalidate];
        self.timer = nil;
        NSTimer *timer = [NSTimer timerWithTimeInterval:self.automaticallyScrollDuration target:self selector:@selector(startScrollAutomtically) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        self.timer = timer;
    }
}

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

- (void)setCurrentIndex:(NSInteger)currentIndex
{
    _currentIndex = currentIndex;
    
    if (_currentIndex < self.imgs.count + 1)
    {
//        NSLog(@"%zd",currentIndex);
        NSInteger index = _currentIndex > 0 ? _currentIndex - 1 : 0;
        self.pageControlView.currentPage = index;
        
        self.titleLabel.hidden = !self.titles.count;
        if (self.titles.count > index)
        {
            self.titleLabel.text = self.titles[index];
        }
        
        return;
    }
    
}

- (void)setImgs:(NSArray *)imgs
{
    _imgs = imgs;
    
    self.pageControlView.hidden = !_imgs.count;
    self.pageControlView.numberOfPages = _imgs.count;
}

- (ADPageControlView *)pageControlView
{
    if (!_pageControlView) {
        _pageControlView = [ADPageControlView pageControlViewWithFrame:CGRectZero];
        [self addSubview:_pageControlView];
    }
    return _pageControlView;
}

- (UILabel *)titleLabel
{
    if (!_titleLabel)
    {
        _titleLabel = [[UILabel alloc] init];
        [self addSubview:_titleLabel];
    }
    return _titleLabel;
}


@end

PageControl控件:

#import <UIKit/UIKit.h>

@interface ADPageControlView : UIView

/**总页数*/
@property(assign,nonatomic) NSInteger numberOfPages;
/**当前页*/
@property(assign,nonatomic) NSInteger currentPage;

/**所有分页dot的背景*/
@property (nonatomic, strong) UIImage *allPageDotImage;
/**当前dot的背景*/
@property (nonatomic, strong) UIImage *currentPageDotImage;

/**所有分页dot的背景颜色*/
@property (nonatomic, strong) UIColor *allPageDotBackgroundColor;
/**当前dot的背景颜色*/
@property (nonatomic, strong) UIColor *currentPageDotColor;

/**dot的圆角,默认是dot点高的一半*/
@property (nonatomic, assign)  CGFloat dotCorner;

+ (instancetype)pageControlViewWithFrame:(CGRect)frame;
/**
 dotsSize:点的大小
 dotsMargin:点之间的间距
 */
+ (instancetype)pageControlViewWithFrame:(CGRect)frame dotsSize:(CGSize)dotsSize dotsMargin:(CGFloat)dotsMargin;
@end
#import "ADPageControlView.h"

#define ADPageControlViewDotViewDefaultWH 10
#define ADPageControlViewDotViewDefaultColor [UIColor grayColor]
#define ADPageControlViewCurrentDotViewColor [UIColor whiteColor]


@interface ADPageControlView()

/**小圆点*/
@property (nonatomic, strong) NSMutableArray *dots;
/**小圆点大小*/
@property (nonatomic, assign)  CGSize dotsSize;
/**小圆点之间的间距*/
@property (nonatomic, assign)  CGFloat dotsMargin;
/**是否完全自定义*/
@property (nonatomic, assign)  BOOL is_custom;

@end

@implementation ADPageControlView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        self.numberOfPages = 0;
        self.currentPage = 0;
    }
    return self;
}

+ (instancetype)pageControlViewWithFrame:(CGRect)frame
{
    return [self pageControlViewWithFrame:frame dotsSize:CGSizeZero dotsMargin:0];
}

+ (instancetype)pageControlViewWithFrame:(CGRect)frame dotsSize:(CGSize)dotsSize dotsMargin:(CGFloat)dotsMargin
{
    ADPageControlView *pageControlView = [[ADPageControlView alloc] initWithFrame:frame];
    pageControlView.dotsSize = dotsSize;
    pageControlView.dotsMargin = dotsMargin;
    pageControlView.is_custom = YES;
    return pageControlView;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    CGFloat dotViewW = 0;
    CGFloat dotViewMargin = 0;
    CGFloat dotViewY = 0;
    CGFloat dotViewH = 0;
    CGFloat dotViewMarginLeft = 0;
    
    dotViewW = self.dotsSize.width > 0 ? self.dotsSize.width : ADPageControlViewDotViewDefaultWH;
    dotViewH = self.dotsSize.height > 0 ? self.dotsSize.height : ADPageControlViewDotViewDefaultWH;
    dotViewMargin = self.dotsMargin > 0 ? self.dotsMargin : (self.bounds.size.width - self.numberOfPages * dotViewW) / (self.numberOfPages - 1);
    dotViewY = (self.bounds.size.height - dotViewH) * 0.5;
    dotViewMarginLeft = (self.bounds.size.width - self.numberOfPages * dotViewW - (self.numberOfPages - 1) * dotViewMargin) * 0.5;
    
    [self.dots enumerateObjectsUsingBlock:^(UIImageView *dotView, NSUInteger idx, BOOL * _Nonnull stop) {
        CGFloat dotViewX = dotViewMarginLeft + idx * (dotViewW + dotViewMargin);
        dotView.frame = CGRectMake(dotViewX, dotViewY, dotViewW, dotViewH);
        
        CGFloat cornerRadius = self.dotCorner > 0 ? self.dotCorner : dotViewH * 0.5;
        dotView.layer.cornerRadius = cornerRadius;
    }];
}

- (void)setNumberOfPages:(NSInteger)numberOfPages
{
    _numberOfPages = numberOfPages;
    
    [self.dots enumerateObjectsUsingBlock:^(UIView *dotView, NSUInteger idx, BOOL * _Nonnull stop) {
        [dotView removeFromSuperview];
    }];
    
    [self.dots removeAllObjects];
    
    for (NSInteger i = 0; i < _numberOfPages; i++)
    {
        UIImageView *dotView = [[UIImageView alloc] init];
        
        dotView.backgroundColor = self.allPageDotBackgroundColor ? self.allPageDotBackgroundColor : ADPageControlViewDotViewDefaultColor;
        
        dotView.image = self.allPageDotImage;
        [self.dots addObject:dotView];
        
        [self addSubview:dotView];
    }
}

- (void)setCurrentPage:(NSInteger)currentPage
{
    _currentPage = currentPage;
    [self.dots enumerateObjectsUsingBlock:^(UIImageView *dotView, NSUInteger idx, BOOL * _Nonnull stop)
    {
        dotView.backgroundColor = self.allPageDotBackgroundColor ? self.allPageDotBackgroundColor : ADPageControlViewDotViewDefaultColor;
        dotView.image = self.allPageDotImage;
        if (idx == _currentPage)
        {
            dotView.backgroundColor = ADPageControlViewCurrentDotViewColor;
            dotView.image = self.currentPageDotImage;
            
        }
    }];
}

- (NSMutableArray *)dots
{
    if (!_dots) {
        _dots = [NSMutableArray array];
    }
    return _dots;
}

@end
原文地址:https://www.cnblogs.com/HJQ2016/p/5929624.html