您的位置:首页 > 移动开发 > IOS开发

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