利用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