iOS網(wǎng)絡開發(fā)之三——iOS 10使用NSJSONSerialization+SDWebImage+UIScrollView實現(xiàn)圖片的循環(huán)播放屏轰、手動滑動

一颊郎、功能

  1. 調(diào)用該類中的初始化方法后,可以初始化循環(huán)播放圖片的ScrollView霎苗、pageControl姆吭,以及設置自動循環(huán)播放的時間間隔。
  2. ScrollView可自動循環(huán)播放唁盏,也可以手動滑動ScrollView内狸。當手動滑動ScrollView時,停止自動循環(huán)播放圖片厘擂,直至不再手動滑動圖片時為止昆淡;
  3. 可手動向右或者向左滑動ScrollView:當從最后一張圖片向右滑動時,進入第一章圖片刽严;當從第一張圖片向左滑動時瘪撇,進入最后一張圖片。
  4. 可設置ScrollView上的圖片是否可以點擊港庄,并設置點擊實現(xiàn)方法倔既。
  5. 使用SDWebImage類庫從后臺服務器(或者網(wǎng)絡上)下載圖片。
  6. 使用蘋果自帶的JSON數(shù)據(jù)解析類NSJSONSerialization來進行json數(shù)據(jù)解析鹏氧。

二渤涌、準備工作

1. 給程序增加SDWebImage依賴

??可以通過cocoaPods安裝SDWebImage依賴,也可以直接前往SDWebImage開源地址將框架下載到本地把还,然后導入到自己的工程中实蓬。

2. 充分明了自己開發(fā)使用的編譯器環(huán)境——即iOS系統(tǒng)版本

??為何要將這一條單獨拉出來說呢?這是因為吊履,從iOS 9(不包含iOS 9)之后安皱,NSURLConnection.h類中從URLRequest中獲取data的如下方法已經(jīng)被棄用了:

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

??根據(jù)幫助文檔說明,將使用NSURLSession.h類中的

[NSURLSession dataTaskWithRequest:completionHandler:]

方法作為替代艇炎。所以酌伊,如果要開發(fā)iOS 5~iOS 9的應用程序,可以繼續(xù)使用[NSURLConnection sendSynchronousRequest:returningResponse:error:]方法來獲取數(shù)據(jù);iOS 9之后的應用程序缀踪,則使用[NSURLSession dataTaskWithRequest:completionHandler:]方法來獲取數(shù)據(jù)居砖。

??本篇文章是基于iOS 10.3來寫的虹脯,所以我將采用[NSURLSession dataTaskWithRequest:completionHandler:]來獲取數(shù)據(jù)。

三奏候、代碼及原理

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;

??因為我是將實現(xiàn)自動循環(huán)的類給封裝了循集,便于在其它類中調(diào)用,所以蔗草,我們需要設置一個標簽咒彤,用于表示scrollView是否可以被點擊。使用enum(枚舉)是一個設置狀態(tài)標簽的比較好的方法咒精。

@protocol SCAutoCircleScrollViewDelegate <NSObject>

@optional

- (void)autoCircleScrollViewDidClickedAtPage : (NSInteger)pageNumber;

@end

??因為設置了ScrollView是否可以點擊镶柱,如果可以點擊,則實現(xiàn)點擊方法狠轻。使用代理來設置這一方法。因為用戶也有可能設置ScrollView不可點擊彬犯,所以將該方法設置為可選的(@optional)向楼,這樣,只有當真正需要實現(xiàn)該方法時才去實現(xiàn)它谐区。

??接下來湖蜕,就是定義一些變量和接口,都是很常規(guī)的方法宋列,此處不再贅述昭抒。如有疑問,可以留言給我炼杖,我將盡力解答灭返。

我們在.h文件中定義的實例和方法,都是公有的坤邪,可以在調(diào)用這個接口的類中通過這個接口的實例來調(diào)用這些實例和方法但通常情況下熙含,我們可能并不希望這樣做,而只是調(diào)用該調(diào)用的方法艇纺,所以可以考慮將除了

@property (nonatomic, assign) SCAutoCircleScrollViewSelectionType autoCircleScrollViewSelectionType;

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

這兩個定義之外的其它定義放到SCAutoCircleScrollView.m文件中怎静,將其變?yōu)樗接小?/p>

??最后,我們定義這個接口中的公有方法黔衡,通過在其它類中實例化這個接口之后蚓聘,通過實例化的類來調(diào)用該方法,以初始化相關(guān)的界面:

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

??這是一個實例方法盟劫,所以只能通過實例對象來調(diào)用夜牡。

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];
    
    //將要自動循環(huán)的視圖(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設置的是可以點擊狀態(tài)氯材,則觸發(fā)響應的方法
    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的偏移量來協(xié)助確認:如果“偏移量/pageWidth”的值是0氢哮,說明當前scrollView的x坐標值為0袋毙,對應的是最后一張圖像,那么當前pageControl.currentPage的值是最后一個(views的數(shù)量-1冗尤,因為pageControl的值是從0開始的听盖,下同);如果“偏移量/pageWidth”的值是“views數(shù)量+1”裂七,說明當前scrollview顯示的是第一張圖片皆看,那么當前pageControl.currentPage的值是0;其它情況是“偏移量/pageWidth” - 1.
    
    //2. 然后背零,根據(jù)_pageControl.currentPage的值腰吟,我們將scrollView滾動到下一張圖上,這個通過設置“[_autoCircleScrollView scrollRectToVisible:rect animated:YES];”的方法來實現(xiàn)徙瓶,并同時增加currentPageNumber的值(currentPageNumber的初始值為當前pageControl.currentPage的值)毛雇。
    
    //3. 最后,如果pageControl.currentPage的值為views的數(shù)量侦镇,那么從第一張圖開始循環(huán)灵疮,并設置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時觸發(fā)
- (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的時候 停止計時器控制的跳轉(zhuǎn)
    [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;
        
    }
    
    //拖動完畢的時候 重新開始計時器控制跳轉(zhuǎn)
    timer = [NSTimer scheduledTimerWithTimeInterval:scheduledtimeInterval target:self selector:@selector(scrollToNextPageAutomatically:) userInfo:nil repeats:YES];
    
}

@end

D. SCAutoCircleScrollView.m文件說明及功能實現(xiàn)原理

??下面壳繁,就是本文的重頭戲之一——使用UIScrollView完成圖片的自動循環(huán)播放及手動滑動震捣。

1. 實現(xiàn)自動循環(huán)的原理

??為了實現(xiàn)在一個ScrollView上自動循環(huán)播放多張圖片,我們需要將顯示這些圖片的UIImageView都添加到ScrollView上闹炉,ImageView的長與寬需要與ScrollView的長與寬保持一致蒿赢。如圖1所示:


圖1

??所謂的自動循環(huán)播放(設置為從左到右自動滑動),就是當播放到最后一張圖片時渣触,依然按照從左到右的方向進入第一張圖片诉植,而不是先向左滑動到第一張圖片(中間會經(jīng)過第一張圖片和最后一張圖片之間的所有圖片,體驗感非常不好)昵观。

??當手動滑動時ScrollView時晾腔,當從第一張圖片往左滑動時,能進入最后一張圖片啊犬;而從最后一張圖片往右滑動時灼擂,直接進入第一張圖片。

??為了完成上述兩個功能觉至,我們需要在ScrollView上添加“圖片數(shù)量+2”個ImageView剔应。比如,我需要使用ScrollView循環(huán)播放4張圖片,則我需要在ScrolLView上添加6個UIImageView.如圖2所示峻贮。

圖2

??下面詳細說明一下如此做的原因:

  1. 按照順序創(chuàng)建ScrollView上的ImageView席怪,一共創(chuàng)建6個——ImageView1~ImageView6;
  2. ImageView1放置圖片4纤控,Image2Image5放置圖片1圖片4挂捻,ImageView6放置圖片1。這樣做的目的是:當我們從圖片1往左滑動時船万,顯示的就是圖片4刻撒;當從圖片4往右手動滑動或者自動滑動時,顯示的是圖片1.

??綜上兩點耿导,我們要做的工作其實就是如何從圖片1——>圖片4声怔,以及從圖片4——>圖片1。

??在SCAutoCircleScrollView.m文件中舱呻,我們先實現(xiàn)SCAutoCircleScrollView.h定義的對外接口的初始化方法“- (id)initThePageControlOnScrollViewWithFrame : (CGRect)pageControlFrame andAutoCircleScrollViewWithFrame : (CGRect)scrollViewFrame withViewsArray : (NSArray*)viewsArray withTimeInterval : (NSTimeInterval)timeInterval”醋火。在這里,我們將外部定義的相關(guān)控件的frame箱吕、含有圖片地址的數(shù)組和自動循環(huán)播放的時間間隔傳遞進來芥驳,并依次在“- (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);

??這是一個很常規(guī)的初始流程:設置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:”方法巴刻,將從網(wǎng)絡上下載下來的圖片放在這個ImageView上,然后將該ImageView添加到ScrollView上蛉签。placeholderImage:參數(shù)放的是如果圖片下載不成功的時候的占位圖片胡陪。按照上面的描述,我們在ImageView1上放的是最后一張照片碍舍,所以我獲取的是scrollViewSourceArray數(shù)組中的最后一個元素柠座。

??對于常規(guī)的情況(比如在tableView中設置默認的cell.image的圖片時),使用“ sd_setImageWithURL:placeholderImage:”方法下載圖片沒有問題片橡。但是如果在scrollView上的ImageView中使用該方法時妈经,會出現(xiàn)一個問題——當加載完頁面之后,pageControl不能被很好的初始化,同時scrollView也不會自動循環(huán)播放吹泡,需要等一段時間之后骤星,pageControl磁能被初始化好,而且只有先手動滑動一下scrollView爆哑,然后scrollView才會自動循環(huán)播放洞难。經(jīng)過多方嘗試,我們將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:塊中編寫趟径。

??關(guān)于pageControl的初始化瘪吏,首先設置其frame,然后設置pageControl要顯示的頁數(shù)(即圖片的總數(shù)量)蜗巧,并設置頁面初始化時pageControl的初始值(第一張圖片對應的是0)掌眠,然后設置pageControl的相關(guān)顏色——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設置的是可以點擊狀態(tài)医咨,則觸發(fā)響應的方法
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTheScrollView:)];
    tap.numberOfTapsRequired = 1;
    tap.numberOfTouchesRequired = 1;
    [self addGestureRecognizer:tap];
  1. 在scrollToNextPageAutomatically:方法中實現(xiàn)scrollView的自動循環(huán)播放

??實現(xiàn)自動循環(huán)播放的原理如下:

a) 首先,判斷scrollView當前在第幾頁架诞,此時可以通過計算scrollView的content的偏移量來協(xié)助確認:如果“偏移量/pageWidth”的值是0拟淮,說明當前scrollView的x坐標值為0,對應的是最后一張圖像侈贷,那么當前pageControl.currentPage的值是最后一個(views的數(shù)量-1惩歉,因為pageControl的值是從0開始的等脂,下同);如果“偏移量/pageWidth”的值是“views數(shù)量+1”撑蚌,說明當前scrollview顯示的是第一張圖片上遥,那么當前pageControl.currentPage的值是0;其它情況是“偏移量/pageWidth” - 1.
b) 然后争涌,根據(jù)_pageControl.currentPage的值粉楚,我們將scrollView滾動到下一張圖上,這個通過設置“[_autoCircleScrollView scrollRectToVisible:rect animated:YES];”的方法來實現(xiàn)亮垫,并同時增加currentPageNumber的值(currentPageNumber的初始值為當前pageControl.currentPage的值)模软。
c) 最后,如果pageControl.currentPage的值為views的數(shù)量饮潦,那么從第一張圖開始循環(huán)燃异,并設置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協(xié)議中的方法實現(xiàn)scrollView手動滑動

??首先稀并,當即將滑動scrollView時仅颇,先終止timer的運行,這樣可以防止手動滑動與自動循環(huán)同時進行碘举,會造成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的值是“圖片數(shù)量+1”李丰,說明當前是在ImageView6,對應圖片1逼泣,則我們就將將scrollView的
contentOffset設置為圖片1對應的值趴泌,并將scrollRectToVisible:設置為顯示圖片1,pageControl.currentPage也設置為圖片1對應的頁面(即0)拉庶。

??如果currentPage的值不是0或者“圖片數(shù)量+1”嗜憔,就正常設置pageControl.currentPage的值即可。

??最后氏仗,當不再手動滑動時吉捶,重啟timer。

E. ViewController.m文件實現(xiàn)從后臺獲取的數(shù)據(jù)的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里面的內(nèi)容為--》%@", [weatherInfo objectForKey:@"location"]);
                                          
                                          NSLog(@"arr里面的內(nèi)容為--》%@", 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之后呐舔,使用系統(tǒng)自帶的框架進行json解析使用如下步驟:

a) 獲取URLRequest(NSURLRequest的實例)币励;
b) 獲取session(NSURLSession的實例);
c) 獲取data(NSURLSessionDataTask的實例珊拼,采用“dataTaskWithRequest:completionHandler:”方法)食呻;
d) 在completionHandler塊中,編寫代碼獲取json數(shù)據(jù)(數(shù)據(jù)是NSDictionary類型澎现,采用“[NSJSONSerialization JSONObjectWithData:[[NSData alloc] initWithData:data] options:NSJSONReadingMutableContainers error:error])”方法獲取);
e) 最后仅胞,采用“[dataTask resume];”方法開啟任務。其中剑辫,datatask為上文創(chuàng)建的NSURLSessionDataTask的實例干旧。

??在“dataTaskWithRequest:completionHandler:”方法的completionHandler塊中,當進行完json解析并獲取到數(shù)據(jù)之后妹蔽,就將數(shù)據(jù)保存到數(shù)組中(我解析出來的是4張圖片在遠程服務器的地址)莱革,然后初始化自動循環(huán)的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];

四、后記

??我已經(jīng)本文的實例代碼上傳到github上讹开,讀者可前往github自行下載實例代碼盅视。本文講述的是我基于自己的后臺獲取數(shù)據(jù)的情況,所以讀者朋友們?nèi)绻苯舆\行實例代碼會出錯旦万,建議使用自己的后臺(如何在Mac OS上搭建自己的后臺闹击?請參考iOS網(wǎng)絡開發(fā)之一——Mac上搭建并配置PHP+Apache+Mysql這篇文章〕伤遥或者修改“dataTaskWithRequest:completionHandler:”方法的completionHandler塊中的json數(shù)據(jù)獲取來源赏半,比如從百度圖片上找一些圖片地址等)。

??同時淆两,我也用hexo+github page的方法搭建了一個個人博客断箫,未來一些文章我也將同步發(fā)布到該博客上,感興趣的朋友可以關(guān)注一下秋冰,給點支持和建議仲义,謝謝。

博客地址點我前往

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剑勾,一起剝皮案震驚了整個濱河市埃撵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌虽另,老刑警劉巖暂刘,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捂刺,居然都是意外死亡谣拣,警方通過查閱死者的電腦和手機募寨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來森缠,“玉大人绪商,你說我怎么就攤上這事「ňǎ” “怎么了格郁?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長独悴。 經(jīng)常有香客問我例书,道長,這世上最難降的妖魔是什么刻炒? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任决采,我火速辦了婚禮,結(jié)果婚禮上坟奥,老公的妹妹穿的比我還像新娘树瞭。我一直安慰自己,他們只是感情好爱谁,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布晒喷。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拧簸,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音爷抓,去河邊找鬼。 笑死阻塑,一個胖子當著我的面吹牛蓝撇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播陈莽,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼渤昌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了传透?” 一聲冷哼從身側(cè)響起耘沼,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤极颓,失蹤者是張志新(化名)和其女友劉穎朱盐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菠隆,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡兵琳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年狂秘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躯肌。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡者春,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出清女,到底是詐尸還是另有隱情钱烟,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布嫡丙,位于F島的核電站拴袭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏曙博。R本人自食惡果不足惜拥刻,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望父泳。 院中可真熱鬧般哼,春花似錦、人聲如沸惠窄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杆融。三九已至黔宛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間擒贸,已是汗流浹背臀晃。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留介劫,地道東北人徽惋。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像座韵,于是被迫代替她去往敵國和親险绘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容