美文网首页
UICollectionView实现无限轮播

UICollectionView实现无限轮播

作者: 代江波 | 来源:发表于2019-03-28 16:59 被阅读0次

    利用UICollectionView封装一个图片轮播器
    .h

    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface CarouselView : UICollectionView
    
    @property (nonatomic, copy) NSArray <NSString *> *imageNames;
    
    - (instancetype)initWithFrame:(CGRect)frame imageNames:(NSArray <NSString *>*)imageNames;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    

    .m

    #import "CarouselView.h"
    #import "CarouselFlowLayout.h"
    #import "CarouselViewCell.h"
    
    @interface CarouselView ()<UICollectionViewDelegate,UICollectionViewDataSource>
    
    @property (nonatomic, assign) NSInteger index;
    
    @end
    
    @implementation CarouselView
    
    NSString * const reuseIdentifier = @"CarouselViewCell";
    
    - (instancetype)initWithFrame:(CGRect)frame imageNames:(NSArray<NSString *> *)imageNames
    {
        CarouselFlowLayout *layout = [[CarouselFlowLayout alloc] init];
        self = [super initWithFrame:frame collectionViewLayout:layout];
        if (self) {
            self.backgroundColor = [UIColor orangeColor];
            self.dataSource = self;
            self.delegate = self;
            self.pagingEnabled = YES;
            self.bounces = NO;
            self.showsHorizontalScrollIndicator = NO;
            self.imageNames = imageNames;
            [self registerClass:[CarouselViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
        }
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
    {
        
        self = [super initWithFrame:frame collectionViewLayout:layout];
        if (self) {
            self.backgroundColor = [UIColor orangeColor];
            self.dataSource = self;
            self.delegate = self;
            self.pagingEnabled = YES;
            self.bounces = NO;
            self.showsHorizontalScrollIndicator = NO;
            [self registerClass:[CarouselViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
        }
        return self;
    }
    
    - (void)setImageNames:(NSArray<NSString *> *)imageNames{
        _imageNames = imageNames;
        
        NSAssert(_imageNames.count > 2, @"轮播图必须大于2张");
        
        [self scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:1 inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    }
    
    
    #pragma mark -- UICollectionViewDataSource
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
        return self.imageNames.count;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        CarouselViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
        
        NSInteger next = indexPath.item - 1;
        next = (self.index + next + self.imageNames.count) % self.imageNames.count;
        
        cell.imageName = self.imageNames[next];
        
        return cell;
    }
    
    #pragma mark -- UICollectionViewDelegate
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
        
    }
    
    #pragma mark -- UISCrollViewDelegate
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
        
        NSInteger offsetX = scrollView.contentOffset.x / scrollView.frame.size.width - 1;
        
        self.index =  (self.index + offsetX + self.imageNames.count) % self.imageNames.count;
        
        dispatch_async(dispatch_get_main_queue(), ^{
            [self scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:1 inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
            [self reloadData];
        });
    }
    
    @end
    

    还有layout,这里只设置一个外边距,也可以自定义一个layout,使用UICollectionView原生的初始化方法就可以了
    .h

    #import <UIKit/UIKit.h>
    @class CarouselFlowLayout;
    NS_ASSUME_NONNULL_BEGIN
    
    @protocol CarouselFlowLayoutDelegate <NSObject>
    
    @optional
    
    /**
     CollectionView外边距
     */
    - (UIEdgeInsets)carouselFlowLayoutEdgeInsets:(CarouselFlowLayout *)layout;
    
    @end
    
    @interface CarouselFlowLayout : UICollectionViewFlowLayout
    
    @property (nonatomic, weak) id<CarouselFlowLayoutDelegate> delegate;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    .m

    #import "CarouselFlowLayout.h"
    
    static UIEdgeInsets const DefaultEdgeInsets = {10, 10, 10, 10};//外边距
    
    @interface CarouselFlowLayout ()
    
    @property (nonatomic, strong) NSMutableArray <UICollectionViewLayoutAttributes *> *attributeArray;
    
    @end
    
    @implementation CarouselFlowLayout
    
    - (instancetype)init{
        self = [super init];
        if (self) {
            self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        }
        return self;
    }
    
    - (void)prepareLayout{
        [super prepareLayout];
        [self.attributeArray removeAllObjects];
        
        NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];
        for (int i = 0; i < itemCount; i ++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            [self.attributeArray addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
        }
    }
    
    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
        return self.attributeArray;
    }
    
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
        
        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
        CGFloat collectionViewWidth = CGRectGetWidth(self.collectionView.frame);
        CGFloat collectionViewHeight = CGRectGetHeight(self.collectionView.frame);
        
        CGFloat width = collectionViewWidth - [self edgeInsets].left - [self edgeInsets].right;
        CGFloat height = collectionViewHeight - [self edgeInsets].top - [self edgeInsets].bottom - [self safeAreaInsets].bottom - [self safeAreaInsets].top;
        
        CGFloat orginX = [self edgeInsets].left + (width + [self edgeInsets].right + [self edgeInsets].left) * indexPath.item;
        CGFloat orginY = [self safeAreaInsets].top + [self edgeInsets].top;
       
        attributes.frame = CGRectMake(orginX, orginY, width, height);
        
        return attributes;
    }
    
    - (CGSize)collectionViewContentSize{
        return CGSizeMake(CGRectGetWidth(self.collectionView.frame) * self.attributeArray.count, 0);
    }
    
    - (UIEdgeInsets)edgeInsets{
        if ([self.delegate respondsToSelector:@selector(carouselFlowLayoutEdgeInsets:)]) {
            return [self.delegate carouselFlowLayoutEdgeInsets:self];
        }
        return DefaultEdgeInsets;
    }
    
    #pragma mark -- iPhoneX 的安全区域
    - (UIEdgeInsets)safeAreaInsets{
        UIEdgeInsets safeAreaInsets = UIEdgeInsetsMake(0, 0, 0, 0);
        if (@available(iOS 11.0, *)) {
            safeAreaInsets = [[UIApplication sharedApplication] delegate].window.safeAreaInsets;
        }
        return safeAreaInsets;
    }
    
    #pragma mark -- 懒加载
    - (NSMutableArray<UICollectionViewLayoutAttributes *> *)attributeArray{
        if (!_attributeArray) {
            _attributeArray = [NSMutableArray array];
        }
        return _attributeArray;
    }
    
    @end
    
    

    相关文章

      网友评论

          本文标题:UICollectionView实现无限轮播

          本文链接:https://www.haomeiwen.com/subject/fmhcbqtx.html