iOS網路開發之三——iOS 10使用NSJSONSerialization+SDWebImage+UIScrollView實現圖片的迴圈播放、手動滑動...

weixin_33785972發表於2017-04-28

一、功能

  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所示:


2556969-626a4d7db92c5e6c.png
圖1

  所謂的自動迴圈播放(設定為從左到右自動滑動),就是當播放到最後一張圖片時,依然按照從左到右的方向進入第一張圖片,而不是先向左滑動到第一張圖片(中間會經過第一張圖片和最後一張圖片之間的所有圖片,體驗感非常不好)。

  當手動滑動時ScrollView時,當從第一張圖片往左滑動時,能進入最後一張圖片;而從最後一張圖片往右滑動時,直接進入第一張圖片。

  為了完成上述兩個功能,我們需要在ScrollView上新增“圖片數量+2”個ImageView。比如,我需要使用ScrollView迴圈播放4張圖片,則我需要在ScrolLView上新增6個UIImageView.如圖2所示。

2556969-16fd1d7565aeda3f.png
圖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的方法搭建了一個個人部落格,未來一些文章我也將同步釋出到該部落格上,感興趣的朋友可以關注一下,給點支援和建議,謝謝。

部落格地址點我前往

相關文章