轮播图播放离线,网络图片

#import @class XRCarouselView;typedef void(^ClickBlock)(NSInteger index);//pageControl的显示位置typedef enum {    PositionNone,          //默认值 == PositionBottomCenter    PositionHide,          //隐藏    PositionTopCenter,      //中上    PositionBottomLeft,    //左下    PositionBottomCenter,  //中下    PositionBottomRight    //右下} PageControlPosition;@protocol XRCarouselViewDelegate/** *  该方法用来处理图片的点击,会返回图片在数组中的索引 *  代理与block二选一即可,若两者都实现,block的优先级高 * *  @param carouselView 控件本身 *  @param index        图片索引 */- (void)carouselView:(XRCarouselView *)carouselView didClickImage:(NSInteger)index;@end/** *  说明:要想正常使用,图片数组imageArray必须设置 *  控件的frame必须设置,xib\sb创建的可不设置 *  其他属性都有默认值,可不设置 */@interface XRCarouselView : UIView/* 这里没有提供修改占位图片的接口,如果需要修改,可直接到.m文件中 修改占位图片名称为你想要显示图片的名称,或者将你想要显示图片的 名称修改为placeholder,因为没实际意义,所以就不提供接口了 */#pragma mark 属性/** *  设置分页控件位置,默认为PositionBottomCenter */@property (nonatomic, assign) PageControlPosition pagePosition;/** *  轮播的图片数组,可以是图片,也可以是网络路径 */@property (nonatomic, strong) NSArray *imageArray;/** *  图片描述的字符串数组,应与图片顺序对应 * *  图片描述控件默认是隐藏的 *  设置该属性后,会取消隐藏,显示在图片底部 */@property (nonatomic, strong) NSArray *describeArray;/** *  图片描述控件的背景颜色,默认为黑色半透明 */@property (nonatomic, strong) UIColor *desLabelBgColor;/** *  图片描述控件的字体,默认为13号字体 */@property (nonatomic, strong) UIFont *desLabelFont;/** *  图片描述控件的文字颜色,默认为白色 */@property (nonatomic, strong) UIColor *desLabelColor;/** *  每一页停留时间,默认为5s,最少1s *  当设置的值小于1s时,则为默认值 */@property (nonatomic, assign) NSTimeInterval time;/** *  点击图片后要执行的操作,会返回图片在数组中的索引 */@property (nonatomic, copy) ClickBlock imageClickBlock;/** *  代理,用来处理图片的点击 */@property (nonatomic, weak) iddelegate;

#pragma mark 构造方法

/**

*  构造方法

*

*  @param imageArray 图片数组

*  @param describeArray 图片描述数组

*

*/

- (instancetype)initWithFrame:(CGRect)frame imageArray:(NSArray *)imageArray;

+ (instancetype)carouselViewWithFrame:(CGRect)frame imageArray:(NSArray *)imageArray;

- (instancetype)initWithImageArray:(NSArray *)imageArray describeArray:(NSArray *)describeArray;

+ (instancetype)carouselViewWithImageArray:(NSArray *)imageArray describeArray:(NSArray *)describeArray;

#pragma mark 方法

/**

*  开启定时器

*  默认已开启,调用该方法会重新开启

*/

- (void)startTimer;

/**

*  停止定时器

*  停止后,如果手动滚动图片,定时器会重新开启

*/

- (void)stopTimer;

/**

*  设置分页控件指示器的图片

*  两个图片都不能为空,否则设置无效

*  不设置则为系统默认

*

*  @param pageImage    其他页码的图片

*  @param currentImage 当前页码的图片

*/

- (void)setPageImage:(UIImage *)pageImage andCurrentImage:(UIImage *)currentImage;

/**

*  设置分页控件指示器的颜色

*  不设置则为系统默认

*

*  @param color    其他页码的颜色

*  @param currentColor 当前页码的颜色

*/

- (void)setPageColor:(UIColor *)color andCurrentPageColor:(UIColor *)currentColor;

/**

*  清除沙盒中的图片缓存

*/

- (void)clearDiskCache;

@end

#import "XRCarouselView.h"#define DEFAULTTIME 3#define Margin 10typedef enum{    DirecNone,    DirecLeft,    DirecRight} Direction;@interface XRCarouselView()//轮播的图片数组

@property (nonatomic, strong) NSMutableArray *images;

//下载的图片字典

@property (nonatomic, strong) NSMutableDictionary *imageDic;

//下载图片的操作

@property (nonatomic, strong) NSMutableDictionary *operationDic;

//滚动方向

@property (nonatomic, assign) Direction direction;

//图片描述控件,默认在底部

@property (nonatomic, strong) UILabel *describeLabel;

//分页控件

@property (nonatomic, strong) UIPageControl *pageControl;

//显示的imageView

@property (nonatomic, strong) UIImageView *currImageView;

//辅助滚动的imageView

@property (nonatomic, strong) UIImageView *otherImageView;

//当前显示图片的索引

@property (nonatomic, assign) NSInteger currIndex;

//将要显示图片的索引

@property (nonatomic, assign) NSInteger nextIndex;

//滚动视图

@property (nonatomic, strong) UIScrollView *scrollView;

//pageControl图片大小

@property (nonatomic, assign) CGSize pageImageSize;

//定时器

@property (nonatomic, strong) NSTimer *timer;

//任务队列

@property (nonatomic, strong) NSOperationQueue *queue;

@end

@implementation XRCarouselView

#pragma mark- 初始化方法

//创建用来缓存图片的文件夹

+ (void)initialize {

NSString *cache = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"XRCarousel"];

BOOL isDir = NO;

BOOL isExists = [[NSFileManager defaultManager] fileExistsAtPath:cache isDirectory:&isDir];

if (!isExists || !isDir) {

[[NSFileManager defaultManager] createDirectoryAtPath:cache withIntermediateDirectories:YES attributes:nil error:nil];

}

}

#pragma mark- frame相关

- (CGFloat)height {

return self.scrollView.frame.size.height;

}

- (CGFloat)width {

return self.scrollView.frame.size.width;

}

#pragma mark- 懒加载

- (NSMutableDictionary *)imageDic{

if (!_imageDic) {

_imageDic = [NSMutableDictionary dictionary];

}

return _imageDic;

}

- (NSMutableDictionary *)operationDic{

if (!_operationDic) {

_operationDic = [NSMutableDictionary dictionary];

}

return  _operationDic;

}

- (NSOperationQueue *)queue {

if (!_queue) {

_queue = [[NSOperationQueue alloc] init];

}

return _queue;

}

- (UIScrollView *)scrollView {

if (!_scrollView) {

_scrollView = [[UIScrollView alloc] init];

_scrollView.pagingEnabled = YES;

_scrollView.bounces = NO;

_scrollView.showsHorizontalScrollIndicator = NO;

_scrollView.showsVerticalScrollIndicator = NO;

_scrollView.delegate = self;

_currImageView = [[UIImageView alloc] init];

_currImageView.userInteractionEnabled = YES;

[_currImageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageClick)]];

[_scrollView addSubview:_currImageView];

_otherImageView = [[UIImageView alloc] init];

[_scrollView addSubview:_otherImageView];

}

return _scrollView;

}

- (UILabel *)describeLabel {

if (!_describeLabel) {

_describeLabel = [[UILabel alloc] init];

_describeLabel.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];

_describeLabel.textColor = [UIColor whiteColor];

_describeLabel.textAlignment = NSTextAlignmentCenter;

_describeLabel.font = [UIFont systemFontOfSize:13];

_describeLabel.hidden = YES;

}

return _describeLabel;

}

- (UIPageControl *)pageControl {

if (!_pageControl) {

_pageControl = [[UIPageControl alloc] init];

_pageControl.hidesForSinglePage = YES;

_pageControl.userInteractionEnabled = NO;

_pageControl.pageIndicatorTintColor = [UIColor colorWithRed:255/255.0 green:255/255.0 blue:255/255.0 alpha:0.5];

_pageControl.currentPageIndicatorTintColor = [UIColor redColor];

}

return _pageControl;

}

#pragma mark- 构造方法

- (instancetype)initWithFrame:(CGRect)frame imageArray:(NSArray *)imageArray {

if (self = [super initWithFrame:frame]) {

self.imageArray = imageArray;

}

return self;

}

+ (instancetype)carouselViewWithFrame:(CGRect)frame imageArray:(NSArray *)imageArray {

return [[self alloc] initWithFrame:frame imageArray:imageArray];

}

- (instancetype)initWithImageArray:(NSArray *)imageArray describeArray:(NSArray *)describeArray {

if (self = [self initWithFrame:CGRectZero imageArray:imageArray]) {

self.describeArray = describeArray;

}

return self;

}

+ (instancetype)carouselViewWithImageArray:(NSArray *)imageArray describeArray:(NSArray *)describeArray {

return [[self alloc] initWithImageArray:imageArray describeArray:describeArray];

}

#pragma mark- --------设置相关方法--------

#pragma mark 设置控件的frame,并添加子控件

- (void)setFrame:(CGRect)frame {

[super setFrame:frame];

[self addSubview:self.scrollView];

[self addSubview:self.describeLabel];

[self addSubview:self.pageControl];

}

#pragma mark 设置滚动方向

- (void)setDirection:(Direction)direction {

if (_direction == direction) return;

_direction = direction;

if (direction == DirecNone) return;

if (direction == DirecRight) {

self.otherImageView.frame = CGRectMake(0, 0, self.width, self.height);

self.nextIndex = self.currIndex - 1;

if (self.nextIndex < 0) self.nextIndex = _images.count - 1;

} else if (direction == DirecLeft){

self.otherImageView.frame = CGRectMake(CGRectGetMaxX(_currImageView.frame), 0, self.width, self.height);

self.nextIndex = (self.currIndex + 1) % _images.count;

}

self.otherImageView.image = self.images[self.nextIndex];

}

#pragma mark 设置图片数组

- (void)setImageArray:(NSArray *)imageArray{

if (!imageArray.count) return;

_imageArray = imageArray;

_images = [NSMutableArray array];

for (int i = 0; i < imageArray.count; i++) {

if ([imageArray[i] isKindOfClass:[UIImage class]]) {

[_images addObject:imageArray[i]];

} else if ([imageArray[i] isKindOfClass:[NSString class]]){

[_images addObject:[UIImage imageNamed:@"placeholder"]];

[self downloadImages:i];

}

}

self.currImageView.image = _images.firstObject;

self.pageControl.numberOfPages = _images.count;

}

#pragma mark 设置描述数组

- (void)setDescribeArray:(NSArray *)describeArray{

_describeArray = describeArray;

//如果描述的个数与图片个数不一致,则补空字符串

if (describeArray && describeArray.count > 0) {

if (describeArray.count < _images.count) {

NSMutableArray *describes = [NSMutableArray arrayWithArray:describeArray];

for (NSInteger i = describeArray.count; i < _images.count; i++) {

[describes addObject:@""];

}

_describeArray = describes;

}

self.describeLabel.hidden = NO;

_describeLabel.text = _describeArray.firstObject;

}

}

#pragma mark 设置scrollView的contentSize

- (void)setScrollViewContentSize {

if (_images.count > 1) {

self.scrollView.contentSize = CGSizeMake(self.width * 3, 0);

self.scrollView.contentOffset = CGPointMake(self.width, 0);

self.currImageView.frame = CGRectMake(self.width, 0, self.width, self.height);

[self startTimer];

} else {

self.scrollView.contentSize = CGSizeZero;

self.scrollView.contentOffset = CGPointZero;

self.currImageView.frame = CGRectMake(0, 0, self.width, self.height);

}

}

#pragma mark 设置图片描述控件

//设置背景颜色

- (void)setDesLabelBgColor:(UIColor *)desLabelBgColor {

_desLabelBgColor = desLabelBgColor;

self.describeLabel.backgroundColor = desLabelBgColor;

}

//设置字体

- (void)setDesLabelFont:(UIFont *)desLabelFont {

_desLabelFont = desLabelFont;

self.describeLabel.font = desLabelFont;

}

//设置文字颜色

- (void)setDesLabelColor:(UIColor *)desLabelColor {

_desLabelColor = desLabelColor;

self.describeLabel.textColor = desLabelColor;

}

#pragma mark 设置pageControl的指示器图片

- (void)setPageImage:(UIImage *)pageImage andCurrentImage:(UIImage *)currentImage {

if (!pageImage || !currentImage) return;

self.pageImageSize = pageImage.size;

[self.pageControl setValue:currentImage forKey:@"_currentPageImage"];

[self.pageControl setValue:pageImage forKey:@"_pageImage"];

}

#pragma mark 设置pageControl的指示器颜色

- (void)setPageColor:(UIColor *)color andCurrentPageColor:(UIColor *)currentColor {

_pageControl.pageIndicatorTintColor = color;

//  设置当前页码指示器的颜色

_pageControl.currentPageIndicatorTintColor = currentColor;

}

#pragma mark 设置pageControl的位置

- (void)setPageControlPosition {

if (_pagePosition == PositionHide) {

_pageControl.hidden = YES;

return;

}

CGSize size;

if (_pageImageSize.width == 0) {//没有设置图片

size = [_pageControl sizeForNumberOfPages:_pageControl.numberOfPages];

size.height = 20;

} else {//设置图片了

size = CGSizeMake(_pageImageSize.width * (_pageControl.numberOfPages * 2 - 1), _pageImageSize.height);

}

_pageControl.frame = CGRectMake(0, 0, size.width, size.height);

if (_pagePosition == PositionNone || _pagePosition == PositionBottomCenter)

_pageControl.center = CGPointMake(self.width * 0.5, self.height - (_describeLabel.hidden? 10 : 30));

else if (_pagePosition == PositionTopCenter)

_pageControl.center = CGPointMake(self.width * 0.5, size.height * 0.5);

else if (_pagePosition == PositionBottomLeft)

_pageControl.frame = CGRectMake(Margin, self.height - (_describeLabel.hidden? size.height : size.height + 20), size.width, size.height);

else

_pageControl.frame = CGRectMake(self.width - Margin - size.width, self.height - (_describeLabel.hidden? size.height : size.height + 20), size.width, size.height);

}

#pragma mark 设置定时器时间

- (void)setTime:(NSTimeInterval)time {

_time = time;

[self startTimer];

}

#pragma mark- --------定时器相关方法--------

- (void)startTimer {

//如果只有一张图片,则直接返回,不开启定时器

if (_images.count <= 1) return;

//如果定时器已开启,先停止再重新开启

if (self.timer) [self stopTimer];

self.timer = [NSTimer timerWithTimeInterval:_time < 1? DEFAULTTIME : _time target:self selector:@selector(nextPage) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

}

- (void)stopTimer {

[self.timer invalidate];

self.timer = nil;

}

- (void)nextPage {

[self.scrollView setContentOffset:CGPointMake(self.width * 2, 0) animated:YES];

}

#pragma mark- -----------其它-----------

#pragma mark 布局子控件

- (void)layoutSubviews {

[super layoutSubviews];

//有导航控制器时,会默认在scrollview上方添加64的内边距,这里强制设置为0

_scrollView.contentInset = UIEdgeInsetsZero;

_scrollView.frame = self.bounds;

_describeLabel.frame = CGRectMake(0, self.height - 20, self.width, 20);

[self setPageControlPosition];

[self setScrollViewContentSize];

}

#pragma mark 图片点击事件

- (void)imageClick {

if (self.imageClickBlock) {

self.imageClickBlock(self.currIndex);

} else if ([_delegate respondsToSelector:@selector(carouselView:didClickImage:)]){

[_delegate carouselView:self didClickImage:self.currIndex];

}

}

#pragma mark 下载网络图片

- (void)downloadImages:(int)index {

NSString *key = _imageArray[index];

//从内存缓存中取图片

UIImage *image = [self.imageDic objectForKey:key];

if (image) {

_images[index] = image;

return;

}

//从沙盒缓存中取图片

NSString *cache = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"XRCarousel"];

NSString *path = [cache stringByAppendingPathComponent:[key lastPathComponent]];

NSData *data = [NSData dataWithContentsOfFile:path];

if (data) {

image = [UIImage imageWithData:data];

_images[index] = image;

[self.imageDic setObject:image forKey:key];

return;

}

//下载图片

NSBlockOperation *download = [self.operationDic objectForKey:key];

if (download) return;

//创建一个操作

download = [NSBlockOperation blockOperationWithBlock:^{

NSURL *url = [NSURL URLWithString:key];

NSData *data = [NSData dataWithContentsOfURL:url];

if (!data) return;

UIImage *image = [UIImage imageWithData:data];

//取到的data有可能不是图片

if (image) {

[self.imageDic setObject:image forKey:key];

self.images[index] = image;

//如果下载的图片为当前要显示的图片,直接到主线程给imageView赋值,否则要等到下一轮才会显示

if (_currIndex == index) [_currImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];

[data writeToFile:path atomically:YES];

}

[self.operationDic removeObjectForKey:key];

}];

[self.queue addOperation:download];

[self.operationDic setObject:download forKey:key];

}

#pragma mark 清除沙盒中的图片缓存

- (void)clearDiskCache {

NSString *cache = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"XRCarousel"];

NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:cache error:NULL];

for (NSString *fileName in contents) {

[[NSFileManager defaultManager] removeItemAtPath:[cache stringByAppendingPathComponent:fileName] error:nil];

}

}

#pragma mark 当图片滚动过半时就修改当前页码

- (void)changeCurrentPageWithOffset:(CGFloat)offsetX {

if (offsetX < self.width * 0.5) {

NSInteger index = self.currIndex - 1;

if (index < 0) index = self.images.count - 1;

_pageControl.currentPage = index;

} else if (offsetX > self.width * 1.5){

_pageControl.currentPage = (self.currIndex + 1) % self.images.count;

} else {

_pageControl.currentPage = self.currIndex;

}

}

#pragma mark- --------UIScrollViewDelegate--------

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

CGFloat offsetX = scrollView.contentOffset.x;

self.direction = offsetX > self.width? DirecLeft : offsetX < self.width? DirecRight : DirecNone;

[self changeCurrentPageWithOffset:offsetX];

}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {

[self stopTimer];

}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{

[self startTimer];

}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

[self pauseScroll];

}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {

[self pauseScroll];

}

- (void)pauseScroll {

//等于1表示没滚动

if (self.scrollView.contentOffset.x / self.width == 1) return;

self.currIndex = self.nextIndex;

self.pageControl.currentPage = self.currIndex;

self.currImageView.frame = CGRectMake(self.width, 0, self.width, self.height);

self.describeLabel.text = self.describeArray[self.currIndex];

self.currImageView.image = self.otherImageView.image;

self.scrollView.contentOffset = CGPointMake(self.width, 0);

}

@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容