iOS 图片轮播
2016-10-26 14:43
134 查看
前言
在手机APP的开中,很多首页需要添加广告位,进行广告图片的轮播。我第一次遇到这种需求是在2014年,当时网上类似的demo也有,但是感觉不好用,于是自己奋笔疾弛写了一个。那时候出道不久,很多东西都是用野路子搞出来的,没有用SDWebImage去缓存网络图片。由于网络请求图片需要一段时间,我先在广告轮播上显示一张本地的默认图片,同时开启一个子线程去下载网络图片,等下载好了然后再刷新显示网络图片。这样做虽然实现了效果,但是走了弯路而且体验不好。在2015年,某个项目中又遇到了广告图片轮播这个需求,很显然不能再用之前那种思路去实现了。当时,网上这种类似的demo很多了,为了赶项目进度我就从网上下载了一个,现在到了2016年又遇上了。在开发中有一种莫名的感觉,某些东西你没搞懂,当时应付过去了,但是以后还老是会来找你。所以,我还是自己好好写一个,以后就再也不用怕它了。虽然现在iOS开发很成熟了,很多东西网上有demo,但是我觉得技术这东西你自己掌握了,才是你的。实现思路
图片轮播其实就是几张图片在进行切换,我们可以想象一下,用scrollView去实现。在scrollView上创建三个imageView, 分别用于显示上一张图片,当前显示图片,下一张图片。当我们向左滑动时,显示上一张图片;向右滑动时,显示下一张图片。下面我们一步步来实现。实现步骤
一、实现左右滑动切换图片
1、图片轮播一般是显示网络图片,所以我们需要用到图片缓存,请先添加SDWebImage。2、新建一个类,继承UIView,命名为:HSImageBanner。在HSImageBanner.m文件中添加图片缓存SDWebImage的头文件:
#import "UIImageView+WebCache.h"
3、初始化一个ScrollView,设置contentSize为其宽度的3倍,然后再ScrollView上添加三个ImageView,代码如下:
#define IMAGEBANNER_WIDTH _scrollView.bounds.size.width #define IMAGEBANNER_HEIGHT _scrollView.bounds.size.height #import "HSImageBanner.h" #import "UIImageView+WebCache.h" @interface HSImageBanner ()<UIScrollViewDelegate> @property (nonatomic, strong) UIImageView *imageView1; //左 @property (nonatomic, strong) UIImageView *imageView2; //中 @property (nonatomic, strong) UIImageView *imageView3; //右 @property (nonatomic, strong) UIScrollView *scrollView; @end @implementation HSImageBanner - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _scrollView = [[UIScrollView alloc] initWithFrame:frame]; _scrollView.showsHorizontalScrollIndicator = NO; _scrollView.showsVerticalScrollIndicator = NO; _scrollView.delegate = self; _scrollView.contentOffset = CGPointMake(IMAGEBANNER_WIDTH, 0); _scrollView.contentSize = CGSizeMake(IMAGEBANNER_WIDTH*3, IMAGEBANNER_HEIGHT); _scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); _scrollView.pagingEnabled = YES; _scrollView.bounces = NO; [self addSubview:_scrollView]; _imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH*0, 0, IMAGEBANNER_WIDTH, IMAGEBANNER_HEIGHT)]; _imageView2 = [[UIImageView alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH*1, 0, IMAGEBANNER_WIDTH, IMAGEBANNER_HEIGHT)]; _imageView3 = [[UIImageView alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH*2, 0, IMAGEBANNER_WIDTH, IMAGEBANNER_HEIGHT)]; [_scrollView addSubview:_imageView1]; [_scrollView addSubview:_imageView2]; [_scrollView addSubview:_imageView3]; } return self; }
4、设置轮播的图片
定义一个可变数组用于存放图片,定义三个整形变量,用于记录显示图片数组中的图片下标。
@interface HSImageBanner ()<UIScrollViewDelegate> { NSInteger index1,index2,index3; NSMutableArray *imageUrls; }
index1、index2、index3就好比三个指针,index1指向图片数组中的最后一张图片,index2指向图片数组中的第一张图片,index2指向图片数组中的最二张图片,与imageView1,imageView2,imageView3相对应。
//设置图片轮播的图片 - (void)setImageBannerImages:(NSArray *)images { index1 = images.count-1; //指向最后一张图片 index2 = 0; //指向最第一张图片 index3 = 1; //指向最第二张图片 //如果只有一张图片,则禁止滑动 if (images.count == 1) { _scrollView.scrollEnabled = NO; index3 = 0; } imageUrls = [[NSMutableArray alloc] init]; for (NSString *string in images) { [imageUrls addObject:[NSURL URLWithString:string]]; } [_imageView1 sd_setImageWithURL:imageUrls[index1] placeholderImage:_placeHolderImage]; [_imageView2 sd_setImageWithURL:imageUrls[index2] placeholderImage:_placeHolderImage]; [_imageView3 sd_setImageWithURL:imageUrls[index3] placeholderImage:_placeHolderImage]; }
5、实现图片左右切换
(1) 向左滑其实就是把指针往图片数组中左移一格,所有的index指针都减1。往左最多只能够移动到图片数组下标为0的位置,当index的值为-1的时候,就说明移动到了数组的最左端,此时应该把index指向数组的最右端。
index1 = index1-1; index2 = index2-1; index3 = index3-1; if (index1 == -1) { index1 = imageUrls.count-1; } if (index2 == -1) { index2 = imageUrls.count-1; } if (index3 == -1) { index3 = imageUrls.count-1; }
同理,向右滑其实就是把指针往图片数组中右移一格,所有的index指针都加1。往右最多只能够移动到图片数组下标为imageUrls.cout的位置,当index的值为imageUrls.cout的时候,就说明移动到了数组的最右端,此时应该把index指向数组的最左端。这样就可以实现循环切换了。
index1 = index1+1; index2 = index2+1; index3 = index3+1; if (index1 == imageUrls.count) { index1 = 0; } if (index2 == imageUrls.count) { index2 = 0; } if (index3 == imageUrls.count) { index3 = 0; }
(2) 那么如何判断用户是向左滑还是往右滑呢?请看我上面的示意图,设置了两个关键点,_scrollView.contentOffset.x=1 倍宽度和_scrollView.contentOffset.x=2倍宽度。当用户往左滑,contentOffset.x就会停留到_scrollView.contentOffset.x=0的位置;当用户往右滑,contentOffset.x就会停留到_scrollView.contentOffset.x=2倍宽度的位置。
if (_scrollView.contentOffset.x == 0) { //左滑 } else if (_scrollView.contentOffset.x == IMAGEBANNER_WIDTH*2) { //右滑 } else return;
(3)最终,我们需要固定ScrollView的contentOffSet的位置,其实我们切换的只是图片,contentOffSet的位置不能变。变的是图片,而不是位置,这里需要转换一下思维。
_scrollView.contentOffset = CGPointMake(IMAGEBANNER_WIDTH, 0);
把这三步的代码综合一下,如下:
#pragma mark - UIScrollView Delegate - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (_scrollView.contentOffset.x == 0) { //左滑 index1 = index1-1; index2 = index2-1; index3 = index3-1; if (index1 == -1) { index1 = imageUrls.count-1; } if (index2 == -1) { index2 = imageUrls.count-1; } if (index3 == -1) { index3 = imageUrls.count-1; } } else if (_scrollView.contentOffset.x == IMAGEBANNER_WIDTH*2) { //右滑 index1 = index1+1; index2 = index2+1; index3 = index3+1; if (index1 == imageUrls.count) { index1 = 0; } if (index2 == imageUrls.count) { index2 = 0; } if (index3 == imageUrls.count) { index3 = 0; } } else return; [_imageView1 sd_setImageWithURL:imageUrls[index1] placeholderImage:_placeHolderImage]; [_imageView2 sd_setImageWithURL:imageUrls[index2] placeholderImage:_placeHolderImage]; [_imageView3 sd_setImageWithURL:imageUrls[index3] placeholderImage:_placeHolderImage]; _pageControl.currentPage = index2; _scrollView.contentOffset = CGPointMake(IMAGEBANNER_WIDTH, 0); }
6、我们来测试一下效果,创建一个对外的调用方法。如果网络比较慢,我们可以设置一张本地的默认图片。
+ (HSImageBanner *)initHSImageBannerWithFrame:(CGRect)frame images:(NSArray *)images placehoderImage:(UIImage *)image { if (images.count == 0) return nil; //没有图片时,直接return HSImageBanner *imageBanner = [[HSImageBanner alloc] initWithFrame:frame]; [imageBanner setImageBannerImages:images]; [imageBanner setPlaceHolderImage:image]; return imageBanner; }
记得在头文件中声明此方法:
#import <UIKit/UIKit.h> @interface HSImageBanner : UIView + (HSImageBanner *)initHSImageBannerWithFrame:(CGRect)frame images:(NSArray *)images placehoderImage:(UIImage *)image; @end
在ViewController.m添加代码:
#import "ViewController.h" #import "HSImageBanner.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSArray *arrImage = @[@"http://ofmw9dt1n.bkt.clouddn.com/image_banner_1.jpg", @"http://ofmw9dt1n.bkt.clouddn.com/image_banner_2.jpg", @"http://ofmw9dt1n.bkt.clouddn.com/image_banner_3.jpg"]; HSImageBanner *imageBanner = [HSImageBanner initHSImageBannerWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 300) images:arrImage placehoderImage:[UIImage imageNamed:@"avator"]]; [self.view addSubview:imageBanner]; } @end
效果图:
二、添加定时器,实现自动滚动
1、添加PageControl定义一个pageControl
@property (nonatomic, strong) UIPageControl *pageControl;
这个比较容易,没有什么可讲解的,直接上代码:
//设置图片轮播的PageControl - (void)setImageBannerPageControl { _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH-imageUrls.count*10, CGRectGetMaxY(_scrollView.frame)-20, 0, 20)]; _pageControl.numberOfPages = imageUrls.count; _pageControl.backgroundColor = [UIColor redColor]; _pageControl.currentPage = 0; [self addSubview:_pageControl]; }
2、添加定时器,自动轮播图片
(1) 在- (id)initWithFrame:(CGRect)frame方法中添加定时器:
[NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(setImageBannerAutoMove) userInfo:nil repeats:YES];
(2) 图片自动轮播其实就是相当于用户向右滑,代码如下:
//设置图片轮播自动滚动 - (void)setImageBannerAutoMove { index1 = index1+1; index2 = index2+1; index3 = index3+1; if (index1 == imageUrls.count) { index1 = 0; } if (index2 == imageUrls.count) { index2 = 0; } if (index3 == imageUrls.count) { index3 = 0; } [_imageView1 sd_setImageWithURL:imageUrls[index1] placeholderImage:_placeHolderImage]; [_imageView2 sd_setImageWithURL:imageUrls[index2] placeholderImage:_placeHolderImage]; [_imageView3 sd_setImageWithURL:imageUrls[index3] placeholderImage:_placeHolderImage]; _pageControl.currentPage = index2; _scrollView.contentOffset = CGPointMake(IMAGEBANNER_WIDTH, 0); }
(3) 在initHSImageBannerWithFrame方法中添加
[imageBanner setImageBannerPageControl];
三、完整的代码
#define IMAGEBANNER_WIDTH _scrollView.bounds.size.width
#define IMAGEBANNER_HEIGHT _scrollView.bounds.size.height
#import "HSImageBanner.h"
#import "UIImageView+WebCache.h"
@interface HSImageBanner ()<UIScrollViewDelegate> { NSInteger index1,index2,index3; NSMutableArray *imageUrls; }
@property (nonatomic, strong) UIImageView *imageView1; //左
@property (nonatomic, strong) UIImageView *imageView2; //中
@property (nonatomic, strong) UIImageView *imageView3; //右
@property (nonatomic, strong) UIImage *placeHolderImage;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIPageControl *pageControl;
@end
@implementation HSImageBanner
+ (HSImageBanner *)initHSImageBannerWithFrame:(CGRect)frame images:(NSArray *)images placehoderImage:(UIImage *)image
{
if (images.count == 0) return nil; //没有图片时,直接return
HSImageBanner *imageBanner = [[HSImageBanner alloc] initWithFrame:frame];
[imageBanner setImageBannerImages:images];
[imageBanner setPlaceHolderImage:image];
[imageBanner setImageBannerPageControl];
return imageBanner;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_scrollView = [[UIScrollView alloc] initWithFrame:frame];
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
_scrollView.delegate = self;
_scrollView.contentOffset = CGPointMake(IMAGEBANNER_WIDTH, 0);
_scrollView.contentSize = CGSizeMake(IMAGEBANNER_WIDTH*3, IMAGEBANNER_HEIGHT);
_scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
_scrollView.pagingEnabled = YES;
_scrollView.bounces = NO;
[self addSubview:_scrollView];
_imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH*0, 0, IMAGEBANNER_WIDTH, IMAGEBANNER_HEIGHT)];
_imageView2 = [[UIImageView alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH*1, 0, IMAGEBANNER_WIDTH, IMAGEBANNER_HEIGHT)];
_imageView3 = [[UIImageView alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH*2, 0, IMAGEBANNER_WIDTH, IMAGEBANNER_HEIGHT)];
[_scrollView addSubview:_imageView1];
[_scrollView addSubview:_imageView2];
[_scrollView addSubview:_imageView3];
[NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(setImageBannerAutoMove) userInfo:nil repeats:YES];
}
return self;
}
//设置图片轮播的图片 - (void)setImageBannerImages:(NSArray *)images { index1 = images.count-1; //指向最后一张图片 index2 = 0; //指向最第一张图片 index3 = 1; //指向最第二张图片 //如果只有一张图片,则禁止滑动 if (images.count == 1) { _scrollView.scrollEnabled = NO; index3 = 0; } imageUrls = [[NSMutableArray alloc] init]; for (NSString *string in images) { [imageUrls addObject:[NSURL URLWithString:string]]; } [_imageView1 sd_setImageWithURL:imageUrls[index1] placeholderImage:_placeHolderImage]; [_imageView2 sd_setImageWithURL:imageUrls[index2] placeholderImage:_placeHolderImage]; [_imageView3 sd_setImageWithURL:imageUrls[index3] placeholderImage:_placeHolderImage]; }
//设置图片轮播自动滚动 - (void)setImageBannerAutoMove { index1 = index1+1; index2 = index2+1; index3 = index3+1; if (index1 == imageUrls.count) { index1 = 0; } if (index2 == imageUrls.count) { index2 = 0; } if (index3 == imageUrls.count) { index3 = 0; } [_imageView1 sd_setImageWithURL:imageUrls[index1] placeholderImage:_placeHolderImage]; [_imageView2 sd_setImageWithURL:imageUrls[index2] placeholderImage:_placeHolderImage]; [_imageView3 sd_setImageWithURL:imageUrls[index3] placeholderImage:_placeHolderImage]; _pageControl.currentPage = index2; _scrollView.contentOffset = CGPointMake(IMAGEBANNER_WIDTH, 0); }
//设置图片轮播的PageControl - (void)setImageBannerPageControl { _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(IMAGEBANNER_WIDTH-imageUrls.count*10, CGRectGetMaxY(_scrollView.frame)-20, 0, 20)]; _pageControl.numberOfPages = imageUrls.count; _pageControl.backgroundColor = [UIColor redColor]; _pageControl.currentPage = 0; [self addSubview:_pageControl]; }
#pragma mark - UIScrollView Delegate - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (_scrollView.contentOffset.x == 0) { //左滑 index1 = index1-1; index2 = index2-1; index3 = index3-1; if (index1 == -1) { index1 = imageUrls.count-1; } if (index2 == -1) { index2 = imageUrls.count-1; } if (index3 == -1) { index3 = imageUrls.count-1; } } else if (_scrollView.contentOffset.x == IMAGEBANNER_WIDTH*2) { //右滑 index1 = index1+1; index2 = index2+1; index3 = index3+1; if (index1 == imageUrls.count) { index1 = 0; } if (index2 == imageUrls.count) { index2 = 0; } if (index3 == imageUrls.count) { index3 = 0; } } else return; [_imageView1 sd_setImageWithURL:imageUrls[index1] placeholderImage:_placeHolderImage]; [_imageView2 sd_setImageWithURL:imageUrls[index2] placeholderImage:_placeHolderImage]; [_imageView3 sd_setImageWithURL:imageUrls[index3] placeholderImage:_placeHolderImage]; _pageControl.currentPage = index2; _scrollView.contentOffset = CGPointMake(IMAGEBANNER_WIDTH, 0); }
@end
DEMO下载
相关文章推荐
- iOS开发UI篇—UIScrollView控件实现图片轮播
- 【iOS开发-62】自定义cell制作团购页面、顶部图片轮播、底部模拟加载更多功能,核心是练习代理模式
- iOS开发UI篇—UIScrollView控件实现图片轮播
- iOS实现图片轮播的简易步骤
- iOS 有关自动轮播图片
- IOS 图片轮播和开始的指导界面
- ios图片轮播
- [IOS]通过UIPageControl+UIScrollView实现图片循环轮播
- (素材源码)猫猫学IOS(十一)UI之图片自动轮播
- iOS开发UI篇—UIScrollView控件实现图片轮播
- iOS开发UI篇—UIScrollView控件实现图片轮播
- IOS UIPageControl & NSTimer定时器 & 图片轮播实例
- iOS开发UI篇—UIScrollView控件实现图片轮播
- iOS实现图片自动轮播展示
- 猫猫学IOS(十一)UI之图片自动轮播
- 【iOS开发-55】图片轮播案例:scrollView的分页、滚动条、利用代理控制定时器和Page Control以及多线程问题
- IOS 图片轮播
- ios 图片轮播详解
- iOS开发UI基础—29UIScrollView控件实现图片轮播
- iOS开发项目实战——Swift实现图片轮播与浏览