iOS网络开发之三——iOS 10使用NSJSONSerialization+SDWebImage+UIScrollView实现图片的循环播放、手动滑动

一、功能

  1. 调用该类中的初始化方法后,可以初始化循环播放图片的ScrollView、pageControl,以及设置自动循环播放的时间间隔。
  2. ScrollView可自动循环播放,也可以手动滑动ScrollView。当手动滑动ScrollView时,停止自动循环播放图片,直至不再手动滑动图片时为止;
  3. 可手动向右或者向左滑动ScrollView:当从最后一张图片向右滑动时,进入第一章图片;当从第一张图片向左滑动时,进入最后一张图片。
  4. 可设置ScrollView上的图片是否可以点击,并设置点击实现方法。
  5. 使用SDWebImage类库从后台服务器(或者网络上)下载图片。
  6. 使用苹果自带的JSON数据解析类NSJSONSerialization来进行json数据解析。

二、准备工作

1. 给程序增加SDWebImage依赖

  可以通过cocoaPods安装SDWebImage依赖,也可以直接前往SDWebImage开源地址将框架下载到本地,然后导入到自己的工程中。

2. 充分明了自己开发使用的编译器环境——即iOS系统版本

  为何要将这一条单独拉出来说呢?这是因为,从iOS 9(不包含iOS 9)之后,NSURLConnection.h类中从URLRequest中获取data的如下方法已经被弃用了:

NSData *response = [NSURLConnection sendSynchronousRequest:requestURL returningResponse:nil error:nil];

  根据帮助文档说明,将使用NSURLSession.h类中的

[NSURLSession dataTaskWithRequest:completionHandler:]

方法作为替代。所以,如果要开发iOS 5~iOS 9的应用程序,可以继续使用[NSURLConnection sendSynchronousRequest:returningResponse:error:]方法来获取数据;iOS 9之后的应用程序,则使用[NSURLSession dataTaskWithRequest:completionHandler:]方法来获取数据。

  本篇文章是基于iOS 10.3来写的,所以我将采用[NSURLSession dataTaskWithRequest:completionHandler:]来获取数据。

三、代码及原理

A. SCAutoCircleScrollView.h文件

#import <UIKit/UIKit.h>

typedef enum {
    
    //设置scrollView上的imageView. Dafult is SCAutoCircleScrollViewSelectionTypeTap
    
    SCAutoCircleScrollViewSelectionTypeTap,   //Can tap the scrollView to get a detail information or new view
    
    SCAutoCircleScrollViewSelectionTypeNone  //Cannot tap the scrollView
    
}SCAutoCircleScrollViewSelectionType;


@protocol SCAutoCircleScrollViewDelegate <NSObject>

@optional

- (void)autoCircleScrollViewDidClickedAtPage : (NSInteger)pageNumber;

@end

@interface SCAutoCircleScrollView : UIView<UIScrollViewDelegate>
{
    
    NSTimer *timer;
    
    NSArray *scrollViewSourceArray;
    
    NSTimeInterval scheduledtimeInterval;
}

@property (nonatomic, strong) UIScrollView *autoCircleScrollView;

@property (nonatomic, strong) UIPageControl *pageControl;

@property (nonatomic, assign) SCAutoCircleScrollViewSelectionType autoCircleScrollViewSelectionType;

@property (nonatomic, assign) id <SCAutoCircleScrollViewDelegate> autoCircleScrollViewDelegate;

- (id)initThePageControlOnScrollViewWithFrame : (CGRect)pageControlFrame andAutoCircleScrollViewWithFrame : (CGRect)scrollViewFrame withViewsArray : (NSArray*)viewsArray withTimeInterval : (NSTimeInterval)timeInterval;

@end

B. SCAutoCircleScrollView.h文件说明

typedef enum {
    SCAutoCircleScrollViewSelectionTypeTap, 
    SCAutoCircleScrollViewSelectionTypeNone
}SCAutoCircleScrollViewSelectionType;

  因为我是将实现自动循环的类给封装了,便于在其它类中调用,所以,我们需要设置一个标签,用于表示scrollView是否可以被点击。使用enum(枚举)是一个设置状态标签的比较好的方法。

@protocol SCAutoCircleScrollViewDelegate <NSObject>

@optional

- (void)autoCircleScrollViewDidClickedAtPage : (NSInteger)pageNumber;

@end

  因为设置了ScrollView是否可以点击,如果可以点击,则实现点击方法。使用代理来设置这一方法。因为用户也有可能设置ScrollView不可点击,所以将该方法设置为可选的(@optional),这样,只有当真正需要实现该方法时才去实现它。

  接下来,就是定义一些变量和接口,都是很常规的方法,此处不再赘述。如有疑问,可以留言给我,我将尽力解答。

我们在.h文件中定义的实例和方法,都是公有的,可以在调用这个接口的类中通过这个接口的实例来调用这些实例和方法但通常情况下,我们可能并不希望这样做,而只是调用该调用的方法,所以可以考虑将除了

@property (nonatomic, assign) SCAutoCircleScrollViewSelectionType autoCircleScrollViewSelectionType;

@property (nonatomic, assign) id <SCAutoCircleScrollViewDelegate> autoCircleScrollViewDelegate;

这两个定义之外的其它定义放到SCAutoCircleScrollView.m文件中,将其变为私有。

  最后,我们定义这个接口中的公有方法,通过在其它类中实例化这个接口之后,通过实例化的类来调用该方法,以初始化相关的界面:

- (id)initThePageControlOnScrollViewWithFrame : (CGRect)pageControlFrame andAutoCircleScrollViewWithFrame : (CGRect)scrollViewFrame withViewsArray : (NSArray*)viewsArray withTimeInterval : (NSTimeInterval)timeInterval;

  这是一个实例方法,所以只能通过实例对象来调用。

C. SCAutoCircleScrollView.m文件

#import "SCAutoCircleScrollView.h"
#import <SDWebImage/UIImageView+WebCache.h>

@implementation SCAutoCircleScrollView


- (id)initThePageControlOnScrollViewWithFrame : (CGRect)pageControlFrame andAutoCircleScrollViewWithFrame : (CGRect)scrollViewFrame withViewsArray : (NSArray*)viewsArray withTimeInterval : (NSTimeInterval)timeInterval {
    
    
    self = [super initWithFrame:scrollViewFrame];
    
    if(self) {
        
        _autoCircleScrollViewSelectionType = SCAutoCircleScrollViewSelectionTypeTap;
        scrollViewSourceArray = viewsArray;
        scheduledtimeInterval = timeInterval;
        self.userInteractionEnabled = YES;
        [self initPageControlWithFrame:pageControlFrame andScrollViewsWithFrame:scrollViewFrame];
        
    }
    
    return  self;
}

- (void)initPageControlWithFrame : (CGRect)pageControlFrame andScrollViewsWithFrame: (CGRect)scrollViewFrame {
    
    CGFloat scrollViewWidth = scrollViewFrame.size.width;
    CGFloat scrollViewHeight = scrollViewFrame.size.height;
    
    //初始化ScrollView
    _autoCircleScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, scrollViewWidth, scrollViewHeight)];
    _autoCircleScrollView.delegate = self;
    _autoCircleScrollView.showsVerticalScrollIndicator = NO;
    _autoCircleScrollView.showsHorizontalScrollIndicator = NO;
    _autoCircleScrollView.pagingEnabled = YES;
    _autoCircleScrollView.contentSize = CGSizeMake(([scrollViewSourceArray count] +2 ) * scrollViewWidth, scrollViewHeight);
    [self addSubview:_autoCircleScrollView];
    
    //将要自动循环的视图(UIImageView)添加到ScrollView上
    UIImageView *firstImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, scrollViewWidth, scrollViewHeight)];
    [firstImageView sd_setImageWithURL:[NSURL URLWithString:[scrollViewSourceArray lastObject]]
                      placeholderImage:nil];
    [_autoCircleScrollView addSubview:firstImageView];
    
    for (int i = 0; i < [scrollViewSourceArray count]; i++) {
        
        UIImageView *imageview = [[UIImageView alloc]initWithFrame:CGRectMake((i+1)*scrollViewWidth, 0, scrollViewWidth, scrollViewHeight)];
        [imageview sd_setImageWithURL:[NSURL URLWithString:[scrollViewSourceArray objectAtIndex:i]]
                     placeholderImage:nil];
        [_autoCircleScrollView addSubview:imageview];
    }
    
    UIImageView *lastImageView = [[UIImageView alloc]initWithFrame:CGRectMake(scrollViewWidth*(scrollViewSourceArray.count+1), 0, scrollViewWidth, scrollViewHeight)];
    [lastImageView sd_setImageWithURL:[NSURL URLWithString:[scrollViewSourceArray objectAtIndex:0]] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {

        //初始化pageControl
        _pageControl = [[UIPageControl alloc]initWithFrame:pageControlFrame];
        _pageControl.numberOfPages = scrollViewSourceArray.count;
        _pageControl.currentPage = 0;
        _pageControl.enabled = YES;
        _pageControl.currentPageIndicatorTintColor = [UIColor redColor];
        _pageControl.pageIndicatorTintColor = [UIColor whiteColor];
        [self addSubview:_pageControl];
        
        [_autoCircleScrollView addSubview:lastImageView];
        
        timer = [NSTimer scheduledTimerWithTimeInterval:scheduledtimeInterval target:self selector:@selector(scrollToNextPageAutomatically:) userInfo:nil repeats:YES];
    }];
    
    
    //初始化时,将scrollView上的view设置为第一个view
    [_autoCircleScrollView scrollRectToVisible:CGRectMake(scrollViewWidth, 0, scrollViewWidth, scrollViewHeight) animated:NO];
    
    //添加一个点击手势,如果ScrollView设置的是可以点击状态,则触发响应的方法
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTheScrollView:)];
    tap.numberOfTapsRequired = 1;
    tap.numberOfTouchesRequired = 1;
    [self addGestureRecognizer:tap];
}



-(void)scrollToNextPageAutomatically:(id)sender
{
    //工作原理:
    
    //1. 首先,判断scrollView当前在第几页,此时可以通过计算scrollView的content的偏移量来协助确认:如果“偏移量/pageWidth”的值是0,说明当前scrollView的x坐标值为0,对应的是最后一张图像,那么当前pageControl.currentPage的值是最后一个(views的数量-1,因为pageControl的值是从0开始的,下同);如果“偏移量/pageWidth”的值是“views数量+1”,说明当前scrollview显示的是第一张图片,那么当前pageControl.currentPage的值是0;其它情况是“偏移量/pageWidth” - 1.
    
    //2. 然后,根据_pageControl.currentPage的值,我们将scrollView滚动到下一张图上,这个通过设置“[_autoCircleScrollView scrollRectToVisible:rect animated:YES];”的方法来实现,并同时增加currentPageNumber的值(currentPageNumber的初始值为当前pageControl.currentPage的值)。
    
    //3. 最后,如果pageControl.currentPage的值为views的数量,那么从第一张图开始循环,并设置currentPageNumber的值为0.
    
    CGFloat pageWidth = _autoCircleScrollView.frame.size.width;
    int currentPage = _autoCircleScrollView.contentOffset.x/pageWidth;
    
    if (currentPage == 0) {
        
        _pageControl.currentPage = scrollViewSourceArray.count-1;
        
    }else if (currentPage == scrollViewSourceArray.count+1) {
        
        _pageControl.currentPage = 0;
        
    }else {
        
        _pageControl.currentPage = currentPage-1;
        
    }
    
    long currentPageNumber = _pageControl.currentPage;
    
    CGSize viewSize = _autoCircleScrollView.frame.size;
    
    CGRect rect = CGRectMake((currentPageNumber+2)*pageWidth, 0, viewSize.width, viewSize.height);
    
    [_autoCircleScrollView scrollRectToVisible:rect animated:YES];
    
    currentPageNumber++;
    
    if (currentPageNumber == scrollViewSourceArray.count) {
        
        _autoCircleScrollView.contentOffset = CGPointMake(0, 0);
        
        currentPageNumber = 0;
        
    }
    
    self.pageControl.currentPage = currentPageNumber;
    
}

//点击scrollView时触发
- (void)tapTheScrollView:(UITapGestureRecognizer *)tapGesture
{
    if (_autoCircleScrollViewSelectionType != SCAutoCircleScrollViewSelectionTypeTap) {
        return;
    }
    if (_autoCircleScrollViewDelegate && [_autoCircleScrollViewDelegate respondsToSelector:@selector(autoCircleScrollViewDidClickedAtPage:)]) {
        
        [_autoCircleScrollViewDelegate autoCircleScrollViewDidClickedAtPage:_pageControl.currentPage];
    }
}

#pragma mark---- UIScrollView delegate methods
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    //开始拖动scrollview的时候 停止计时器控制的跳转
    [timer invalidate];
    
    
    timer = nil;
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    
    CGFloat width = _autoCircleScrollView.frame.size.width;
    CGFloat height = _autoCircleScrollView.frame.size.height;
    
    
    //当手指滑动scrollview,而scrollview减速停止的时候 开始计算当前的图片的位置
    int currentPage = _autoCircleScrollView.contentOffset.x/width;
    
    if (currentPage == 0) {
        
        _autoCircleScrollView.contentOffset = CGPointMake(width * scrollViewSourceArray.count, 0);
        
        [_autoCircleScrollView scrollRectToVisible:CGRectMake(scrollViewSourceArray.count * width, 0, width, height) animated:YES];
        
        _pageControl.currentPage = scrollViewSourceArray.count-1;
        
    }else if (currentPage == scrollViewSourceArray.count+1) {
        
        _autoCircleScrollView.contentOffset = CGPointMake(width, 0);
        
        [_autoCircleScrollView scrollRectToVisible:CGRectMake(width, 0, width, height) animated:YES];
        
        _pageControl.currentPage = 0;
        
    }else {
        
        _pageControl.currentPage = currentPage-1;
        
    }
    
    //拖动完毕的时候 重新开始计时器控制跳转
    timer = [NSTimer scheduledTimerWithTimeInterval:scheduledtimeInterval target:self selector:@selector(scrollToNextPageAutomatically:) userInfo:nil repeats:YES];
    
}

@end

D. SCAutoCircleScrollView.m文件说明及功能实现原理

  下面,就是本文的重头戏之一——使用UIScrollView完成图片的自动循环播放及手动滑动。

1. 实现自动循环的原理

  为了实现在一个ScrollView上自动循环播放多张图片,我们需要将显示这些图片的UIImageView都添加到ScrollView上,ImageView的长与宽需要与ScrollView的长与宽保持一致。如图1所示:


图1

  所谓的自动循环播放(设置为从左到右自动滑动),就是当播放到最后一张图片时,依然按照从左到右的方向进入第一张图片,而不是先向左滑动到第一张图片(中间会经过第一张图片和最后一张图片之间的所有图片,体验感非常不好)。

  当手动滑动时ScrollView时,当从第一张图片往左滑动时,能进入最后一张图片;而从最后一张图片往右滑动时,直接进入第一张图片。

  为了完成上述两个功能,我们需要在ScrollView上添加“图片数量+2”个ImageView。比如,我需要使用ScrollView循环播放4张图片,则我需要在ScrolLView上添加6个UIImageView.如图2所示。

图2

  下面详细说明一下如此做的原因:

  1. 按照顺序创建ScrollView上的ImageView,一共创建6个——ImageView1~ImageView6;
  2. ImageView1放置图片4,Image2Image5放置图片1图片4,ImageView6放置图片1。这样做的目的是:当我们从图片1往左滑动时,显示的就是图片4;当从图片4往右手动滑动或者自动滑动时,显示的是图片1.

  综上两点,我们要做的工作其实就是如何从图片1——>图片4,以及从图片4——>图片1。

  在SCAutoCircleScrollView.m文件中,我们先实现SCAutoCircleScrollView.h定义的对外接口的初始化方法“- (id)initThePageControlOnScrollViewWithFrame : (CGRect)pageControlFrame andAutoCircleScrollViewWithFrame : (CGRect)scrollViewFrame withViewsArray : (NSArray*)viewsArray withTimeInterval : (NSTimeInterval)timeInterval”。在这里,我们将外部定义的相关控件的frame、含有图片地址的数组和自动循环播放的时间间隔传递进来,并依次在“- (void)initPageControlWithFrame : (CGRect)pageControlFrame andScrollViewsWithFrame: (CGRect)scrollViewFrame”方法中初始化ScrollView、PageControl和ImageView。接下来我们就重点讲一下“- (void)initPageControlWithFrame : (CGRect)pageControlFrame andScrollViewsWithFrame: (CGRect)scrollViewFrame”里面的方法。

  1. 初始化ScrollView
_autoCircleScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, scrollViewWidth, scrollViewHeight)];
_autoCircleScrollView.delegate = self;
_autoCircleScrollView.showsVerticalScrollIndicator = NO;
_autoCircleScrollView.showsHorizontalScrollIndicator = NO;
_autoCircleScrollView.pagingEnabled = YES;
_autoCircleScrollView.contentSize = CGSizeMake(([scrollViewSourceArray count] +2 ) * scrollViewWidth, scrollViewHeight);

  这是一个很常规的初始流程:设置frame——>设置delegate——>设置是否显示水平和竖直滚动条——>设置是否分页显示(pagingEnabled的值设置为YES,一次滚动一张图片的范围)——>设置ScrollView的ContentSize(ContentSize表示scrollView显示的整个长度和宽度)。

  1. 初始化ImageView、pageControl和timer

  接下来,我们要初始化ImageView并将其加到ScrollView上。添加ImageView1~ImageView5的方法类似,此处只按照添加ImageView1的方法讲解:

UIImageView *firstImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, scrollViewWidth, scrollViewHeight)];
    
    [firstImageView sd_setImageWithURL:[NSURL URLWithString:[scrollViewSourceArray lastObject]]
                      placeholderImage:nil];
    
    [_autoCircleScrollView addSubview:firstImageView];

  首先初始化一个ImageView,然后使用SDWebImage中的“ sd_setImageWithURL:placeholderImage:”方法,将从网络上下载下来的图片放在这个ImageView上,然后将该ImageView添加到ScrollView上。placeholderImage:参数放的是如果图片下载不成功的时候的占位图片。按照上面的描述,我们在ImageView1上放的是最后一张照片,所以我获取的是scrollViewSourceArray数组中的最后一个元素。

  对于常规的情况(比如在tableView中设置默认的cell.image的图片时),使用“ sd_setImageWithURL:placeholderImage:”方法下载图片没有问题。但是如果在scrollView上的ImageView中使用该方法时,会出现一个问题——当加载完页面之后,pageControl不能被很好的初始化,同时scrollView也不会自动循环播放,需要等一段时间之后,pageControl磁能被初始化好,而且只有先手动滑动一下scrollView,然后scrollView才会自动循环播放。经过多方尝试,我们将ImageVeiw6的初始化方法修改成如下方法,就可以解决这个问题。具体原因我还没有想明白,如果有哪位朋友了解,还请不吝赐教。

 UIImageView *lastImageView = [[UIImageView alloc]initWithFrame:CGRectMake(scrollViewWidth*(scrollViewSourceArray.count+1), 0, scrollViewWidth, scrollViewHeight)];
    
    [lastImageView sd_setImageWithURL:[NSURL URLWithString:[scrollViewSourceArray objectAtIndex:0]] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
        
        
        //初始化pageControl
        _pageControl = [[UIPageControl alloc]initWithFrame:pageControlFrame];
        _pageControl.numberOfPages = scrollViewSourceArray.count;
        _pageControl.currentPage = 0;
        _pageControl.enabled = YES;
        _pageControl.currentPageIndicatorTintColor = [UIColor redColor];
        _pageControl.pageIndicatorTintColor = [UIColor whiteColor];
        
        [self addSubview:_pageControl];
        
        [_autoCircleScrollView addSubview:lastImageView];
        
        timer = [NSTimer scheduledTimerWithTimeInterval:scheduledtimeInterval target:self selector:@selector(scrollToNextPageAutomatically:) userInfo:nil repeats:YES];
    }];

  我们在下载图片1时,使用SDWebImage中的“sd_setImageWithURL:placeholderImage:completed:”方法,同时将pageControl的初始化方法、定时器timer的初始化方法、将ImageView6放到ScrollView上的方法都放到completed:块中编写。

  关于pageControl的初始化,首先设置其frame,然后设置pageControl要显示的页数(即图片的总数量),并设置页面初始化时pageControl的初始值(第一张图片对应的是0),然后设置pageControl的相关颜色——currentPageIndicatorTintColor表示的是当前被选择时的颜色,pageIndicatorTintColor指的是未被选择的颜色。

  最后,我们设置ScrollView刚被初始化时显示哪一张图片(scrollRectToVisible:方法表示显示的是scrollView的那个width和height,我们还会在后面使用到它。因为我们希望初始化scrollView时显示图片1,而图片1是被加在ImageView2上的,所以设置width和height为CGRectMake(scrollViewWidth, 0, scrollViewWidth, scrollViewHeight)),并添加一个点击手势。

//初始化时,将scrollView上的view设置为第一个view
    [_autoCircleScrollView scrollRectToVisible:CGRectMake(scrollViewWidth, 0, scrollViewWidth, scrollViewHeight) animated:NO];
    
    
    //添加一个点击手势,如果ScrollView设置的是可以点击状态,则触发响应的方法
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTheScrollView:)];
    tap.numberOfTapsRequired = 1;
    tap.numberOfTouchesRequired = 1;
    [self addGestureRecognizer:tap];
  1. 在scrollToNextPageAutomatically:方法中实现scrollView的自动循环播放

  实现自动循环播放的原理如下:

a) 首先,判断scrollView当前在第几页,此时可以通过计算scrollView的content的偏移量来协助确认:如果“偏移量/pageWidth”的值是0,说明当前scrollView的x坐标值为0,对应的是最后一张图像,那么当前pageControl.currentPage的值是最后一个(views的数量-1,因为pageControl的值是从0开始的,下同);如果“偏移量/pageWidth”的值是“views数量+1”,说明当前scrollview显示的是第一张图片,那么当前pageControl.currentPage的值是0;其它情况是“偏移量/pageWidth” - 1.
b) 然后,根据_pageControl.currentPage的值,我们将scrollView滚动到下一张图上,这个通过设置“[_autoCircleScrollView scrollRectToVisible:rect animated:YES];”的方法来实现,并同时增加currentPageNumber的值(currentPageNumber的初始值为当前pageControl.currentPage的值)。
c) 最后,如果pageControl.currentPage的值为views的数量,那么从第一张图开始循环,并设置pageControl的currentPageNumber的值为0.

  我们在如下的代码中完成原理a)的工作:

CGFloat pageWidth = _autoCircleScrollView.frame.size.width;
int currentPage = _autoCircleScrollView.contentOffset.x/pageWidth;
    
if (currentPage == 0) {
        
    _pageControl.currentPage = scrollViewSourceArray.count-1;
        
}else if (currentPage == scrollViewSourceArray.count+1) {
        
    _pageControl.currentPage = 0;
        
}else {
        
    _pageControl.currentPage = currentPage-1;
        
}

  然后,在如下代码中完成原理b)的工作。

long currentPageNumber = _pageControl.currentPage;
    
CGSize viewSize = _autoCircleScrollView.frame.size;
    
CGRect rect = CGRectMake((currentPageNumber+2)*pageWidth, 0, viewSize.width, viewSize.height);
    
[_autoCircleScrollView scrollRectToVisible:rect animated:YES];
    
currentPageNumber++;

  最后,在如下代码中完成原理c)的工作。

if (currentPageNumber == scrollViewSourceArray.count) {
        
    _autoCircleScrollView.contentOffset = CGPointMake(0, 0);
        
    currentPageNumber = 0;
        
}
    
self.pageControl.currentPage = currentPageNumber;

  1. 使用UIScrollViewDelegate协议中的方法实现scrollView手动滑动

  首先,当即将滑动scrollView时,先终止timer的运行,这样可以防止手动滑动与自动循环同时进行,会造成ImageView的突变:

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [timer invalidate];
    timer = nil;
}

  然后,计算当前显示的是第几张图片,使用如下的方法:

int currentPage = _autoCircleScrollView.contentOffset.x/width;

  如果currentPage的值是0,说明当前是在ImageView1,对应图片4,则我们就将scrollView的
contentOffset设置为图片4对应的值,并将scrollRectToVisible:设置为显示图片4,pageControl.currentPage也设置为图片4对应的页面(即3)。

  如果currentPage的值是“图片数量+1”,说明当前是在ImageView6,对应图片1,则我们就将将scrollView的
contentOffset设置为图片1对应的值,并将scrollRectToVisible:设置为显示图片1,pageControl.currentPage也设置为图片1对应的页面(即0)。

  如果currentPage的值不是0或者“图片数量+1”,就正常设置pageControl.currentPage的值即可。

  最后,当不再手动滑动时,重启timer。

E. ViewController.m文件实现从后台获取的数据的json解析,并初始化scrollView

//json解析
    
    NSURLRequest *requestURL = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/exerciseAutoScrollView/exerciseAutoScrollView.php"]];
    
    
    NSURLSession *session = [NSURLSession sharedSession];
    
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestURL
                                                completionHandler:
                                      ^(NSData *data, NSURLResponse *response, NSError *error) {
                                          
                                          
                                          NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:[[NSData alloc]
                                                                                                            initWithData:data]
                                                                                                   options:NSJSONReadingMutableContainers
                                                                                                     error:nil];
                                          
                                          //NSDictionary *weatherInfo = [jsonData objectForKey:@"IMG_003"];
                                          
                                          NSArray *arr = [[NSArray alloc]initWithArray:[jsonData allKeys]];
                                          
                                          // NSLog(@"arr里面的内容为--》%@", [weatherInfo objectForKey:@"location"]);
                                          
                                          NSLog(@"arr里面的内容为--》%@", arr);
                                          
                                          NSMutableArray *textArr = [[NSMutableArray alloc]initWithCapacity:10];
                                          
                                          for(int i =0; i < [arr count]; i++) {
                                              
                                              NSDictionary *imageDataInfoDic = [jsonData objectForKey:[arr objectAtIndex:i]];
                                              
                                              [textArr addObject:[imageDataInfoDic objectForKey:@"location"]];
                                          }
                                          
                                      }];
    // 使用resume方法启动任务
    [dataTask resume];

  iOS 9之后,使用系统自带的框架进行json解析使用如下步骤:

a) 获取URLRequest(NSURLRequest的实例);
b) 获取session(NSURLSession的实例);
c) 获取data(NSURLSessionDataTask的实例,采用“dataTaskWithRequest:completionHandler:”方法);
d) 在completionHandler块中,编写代码获取json数据(数据是NSDictionary类型,采用“[NSJSONSerialization JSONObjectWithData:[[NSData alloc] initWithData:data] options:NSJSONReadingMutableContainers error:error])”方法获取);
e) 最后,采用“[dataTask resume];”方法开启任务。其中,datatask为上文创建的NSURLSessionDataTask的实例。

  在“dataTaskWithRequest:completionHandler:”方法的completionHandler块中,当进行完json解析并获取到数据之后,就将数据保存到数组中(我解析出来的是4张图片在远程服务器的地址),然后初始化自动循环的scrollView:

sourceArray = [[NSArray alloc]initWithArray:textArr];
SCAutoCircleScrollView *scrollView = [[SCAutoCircleScrollView alloc]initThePageControlOnScrollViewWithFrame:CGRectMake(deviceScreenWidth / 2, 100, deviceScreenWidth / 2, 30) andAutoCircleScrollViewWithFrame:CGRectMake(0, 0, deviceScreenWidth, 130) withViewsArray:sourceArray withTimeInterval : 2.0];
scrollView.autoCircleScrollViewDelegate = self;
[self.view addSubview:scrollView];

四、后记

  我已经本文的实例代码上传到github上,读者可前往github自行下载实例代码。本文讲述的是我基于自己的后台获取数据的情况,所以读者朋友们如果直接运行实例代码会出错,建议使用自己的后台(如何在Mac OS上搭建自己的后台?请参考iOS网络开发之一——Mac上搭建并配置PHP+Apache+Mysql这篇文章。或者修改“dataTaskWithRequest:completionHandler:”方法的completionHandler块中的json数据获取来源,比如从百度图片上找一些图片地址等)。

  同时,我也用hexo+github page的方法搭建了一个个人博客,未来一些文章我也将同步发布到该博客上,感兴趣的朋友可以关注一下,给点支持和建议,谢谢。

博客地址点我前往

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

推荐阅读更多精彩内容