iOS開發--輪播圖(無限循環)新玩法--視差輪播--無限循環的新思路(兩個UIImageView足矣)

老賴本來說要更新iOS學習課程,可走神弄了一下午的輪播圖,這裏把整個過程記錄下來吧,對有需要的好朋友,或許有點兒小小的幫助.

首先說,輪播圖,這個東西,做開發的應該都會,不過實現的的邏輯思路有所不同.

方法一

比方說固定有5張圖,最基本的實現方法就是,在scrollView上添加7張圖片,排列方式是:

五一二三四五一

當圖片滑到最左邊,也就是”五”這個圖片的時候,讓scrollView調用setContentOffset 這個方法,直接跳轉到倒數第二個張上面,也是”五”,所以肉眼是看不出scrollView移動的.

注意這裏的跳,不能開啓動畫.同理,當scrollView滑到最後一個,讓它瞬間跳到左邊的”一”這張上去…這樣就實現了無限循環滾動.

這個方法,非常巧妙,平面理解有點兒費勁,不過老賴理解之—>你拿張紙條,讓它收尾相連,形成一個空間的圓圈閉環,這樣,估計你瞬間裏明白了這個瞬間跳轉是怎麼回事了!

先來看看這種方法的效果圖:如下
這裏寫圖片描述

看了上面的效果圖後,問題也就出來了,這裏有少量的圖片,可以直接把圖片的imageView加載到scrollView上.但是,如果圖片多呢,50張?100張?創建100個imageView加到scrollView上,內存也吃不消吧.

對了,有好朋友,應該想到了,可以用–複用機制!

方法二:

複用機制的好處,在tableView用的淋漓盡致,做輪播圖,咱們用它的親戚,collectionView.因爲系統空間本身就有複用機制,無論你加載多少照片,它只創建了兩個cell,這樣就大大的優化APP性能.
具體的詳情,老賴這裏不詳細闡述了,照舊貼出相關鏈接:

http://www.cnblogs.com/wendingding/p/3890850.html
http://www.cnblogs.com/wendingding/p/3890953.html

這兩篇是有關collectionView做輪播圖的,當然,這是大神的系列,好朋友們,可以翻看前後篇,系統的學習一下.

方法三:
說了這麼多,老賴的粉絲都等急了吧,哈哈,別說話,先那啥…..呃,上效果圖唄!
這裏寫圖片描述
看了效果圖,有好朋友說,搞什麼啊,跟上面不是一毛一樣的麼?還沒有人家的360°旋轉切換文字呢!!
咳咳,那不是重點好麼,重點是切換下一張圖片,是有視差效果!!!視差效果!!!視差效果!!

一張圖片壓着另一張圖片上面,這個效果在iPhone裏就有,好像是調用系統相冊裏面切換照片時候的效果.
另外,重點來了!!!無論你多少張照片,老賴我這裏只有用了兩個UIImageView!沒錯,就是兩個,一樣完成無限輪播!

這個*不能裝過咯,老賴我還是低調的,其實思路也很清晰,接下來,就聽有北京著名賴人—-老賴娓娓道來之:

首先咱們還是先聲明一些屬性

//滾動視圖
@property (nonatomic, strong) UIscrollView   *scrollView;
//第一個圖片
@property (nonatomic, strong) UIImageView    *firstImageView;
//第二個圖片
@property (nonatomic, strong) UIImageView    *secondImageView;
//圖片的數據源
@property (nonatomic, strong) NSMutableArray *imageDataSource;
//頁面控制器
@property (nonatomic, strong) UIPageControl  *pageController;
//時間控制器
@property (nonatomic, strong) NSTimer        *timer;
有好朋友打眼一看,就知道老賴不專業了,整兩張圖片的ImageView,命名竟然用first和second這low的名字.好吧,老賴承認,時間緊,任務重,各種原因吧,總之就這樣了,愛咋咋地,跟老賴講道理,嗯哼?

接下來就是對對象的初始化,老賴給代碼都註釋了

//添加滾動視圖
    UIscrollView *scrollView = [[UIscrollView alloc] initWithFrame:self.bounds];
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.pagingEnabled = YES;
    scrollView.contentOffset = CGPointMake(CGRectGetWidth(self.frame), 0);
    scrollView.delegate = self;
    scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.frame) * 3, CGRectGetHeight(self.frame));
    //添加點擊事件
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapClick:)];
    [scrollView addGestureRecognizer:tap];
    //添加到父視圖上
    [self addSubview:scrollView];
    self.scrollView = scrollView;

    //給滾動視圖添加兩個UIImageView
    UIImageView *firstImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    self.firstImageView = firstImageView;
    UIImageView *secondImageView = [[UIImageView alloc] initWithFrame:self.bounds];
    self.secondImageView = secondImageView;

    [self.scrollView addSubview:secondImageView];
    [self.scrollView addSubview:firstImageView];

    //先設置第一張圖片的位置,在滾動視圖的正中央
    self.firstImageView.frame = CGRectMake(CGRectGetWidth(self.frame), 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));

    //設置pageController(這裏可以根據個人喜好自定義)
    UIPageControl *pageController = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), 20)];

    pageController.center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) - 20);

    //設置pageController 的頁數
    pageController.numberOfPages = self.imageDataSource.count;

    pageController.currentPage = 0;
    [self addSubview:pageController];
    self.pageController = pageController;
.

其實老賴不喜歡,貼這麼多代碼…好多好朋友都跟老賴一樣,代碼一多,看不下去.那老賴我就把重要部分的代碼,簡短的貼出來,並解釋說明之,最後,會把源碼地址貼出來.

這裏要說明一下剛纔那一長串代碼,scrollView的contentSize是3個屏幕寬,並且初始讓scrollView的可視部分在最中間, 正好可以用來左右滾動.

然後,第一張圖片的放到最中間,並且,它的位置是固定的,也就是說,第一張圖片跟隨scrollView滾動.
那第二張圖片,就扮演滑動圖片後,將要出現的視圖了.

首先假定我們手指,從左往右滑動,也就是看看左邊的圖片,就是上一張圖片:

    //添加將要出現的視圖(其實就是第二張圖片)的中心點X座標
    static float nextImageViewCenterX = 0.f;

    //判斷滾動方向
    if (scrollView.contentOffset.x < CGRectGetWidth(self.frame)) {
        //從左往右
        nextImageViewCenterX = (CGRectGetWidth(self.frame)  + offsetX) / 2;
        _nextImageIndex = _currentImageIndex - 1;
    }
.
上面的代碼是用來幹嘛的呢?有好朋友一樣就看出來了!對,就是讓第二張圖片跟隨第一張圖片也就是scrollView移動的:
GPoint center = CGPointMake(nextImageViewCenterX , CGRectGetHeight(self.frame)/2);
//實時更新第二張圖片的位置
self.secondImageView.center = center ;
.
那有好朋友要問了,爲什麼第二張圖片的中心點的計算,用後面的那個等式呢?
這裏簡要解釋一下視差的效果實現原理:
當第一張圖片將要滾動的時候,第二章圖片其實已經有一半在我們屏幕上.然後隨着第一張圖片移動,第一張圖片移動一橫屏,讓第二章圖片跟着移動半屏的距離就行了!

But!!真的是老賴上面說的那樣嗎?其實不是!不要輕易相信老賴!

之所以說不是,是因爲假設第一張圖片往右走,如果你讓第二張圖片也往右走,鬆開手後,效果完全不是這樣.這裏其實是讓第二張圖像左走.

對,相對於scrollView來說,第二章圖片要向左走!爲什麼呢?因爲整個scrollView都向右走,鬆手後,scrollView的可視位置,由中間變成了最左邊,此時只有讓第二章圖片也出現在最左邊也能完全展示出來它.第二張圖片的初始位置是在一半屏幕寬度上的,所以它要往左走到零!

接着來說,圖片加載相關.之前聲明瞭如下的成員變量:

    //記錄當前圖片下標
    int _currentImageIndex;
    //記錄下一張圖片下標
    int _nextImageIndex;
.
當視圖滾動後,直接可以通過下一張圖片的下標從數據源裏取圖片
self.secondImageView.image = self.imageDataSource[_nextImageIndex];
.
然後,滾動,滾動,滾動,當圖片是最後一張,再往後滾,或者當圖片第一張,再往前滾的時候,就需要輪播,思想還是跳轉:
    if (_nextImageIndex == -1) {
         _nextImageIndex = (int)self.imageDataSource.count - 1;
    }else if (_nextImageIndex == self.imageDataSource.count){
         _nextImageIndex = 0;
    }
.
實現了圖片的輪播加載後,可能有細心的好朋友們,一直疑問着呢…你scrollView只有三個屏幕的寬度,只能往左滾動一次,怎麼實現輪播呢?
估計問這個問題的好朋友,沒有細心看方法一,不錯,這裏也要讓scrollView瞬間跳轉!只不過,這裏無論往左還是往右,scrollView跳轉的位置都是最中心!也就是重新回到原來的位置.不過這裏特別需要注意的是:在跳轉回之前,一定要把中間位置上的第一張圖片,設置成現在第二張圖片,這樣視覺上纔不會有跳躍!
// 減速完成(分頁滑動是會減速的)
- (void)scrollViewDidEndDecelerating:(UIscrollView *)scrollView
{
    [self endRollscrollViewWith:scrollView];
}
// 滑動動畫結束 setContentOffset: animated:YES 動畫結束調用
- (void)scrollViewDidEndScrollingAnimation:(UIscrollView *)scrollView{
    [self endRollscrollViewWith:scrollView];
}
//結束滾動後,重置頁面
-(void)endRollscrollViewWith:(UIscrollView *)scrollView
{
    //判斷是否完成翻頁
    if (scrollView.contentOffset.x != CGRectGetWidth(self.frame)) {
        //更新當前圖片下標
        _currentImageIndex = _nextImageIndex;
        //給第一張相框添加圖片
        self.firstImageView.image = self.imageDataSource[_currentImageIndex];
        //讓視圖瞬間回到中間位置
        [self.scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.frame), 0)];
        //更新page
        self.pageController.currentPage = _currentImageIndex;
    }
}
.
看到這裏,想必你大概也明白了這個視差輪播,以及只用兩個UIImageView就能無限輪播的原理了吧!
那老賴也不賣關子了,把源碼放上來吧:另外說一下,這裏封裝了兩個,一個是代理協議回調的,一個是Block回調的,好朋友們各取所需吧:
https://github.com/wswei99/WSWscrollView

下面講的是一些基本用法,demo裏面的用例已經足夠了,聰明的好朋友們,不用往下看了,帥的小夥伴們繼續跟着老賴往下走吧!

先說說協議代理封裝的:

@property (nonatomic, assign)  id<WSWscrollViewDelegate> delegate;
@property (nonatomic, assign)  id<WSWscrollViewDataSource> dataSource;
    //@required
    //給輪播視圖提供數據源數組
- (NSArray *)imagesArrayForWSWscrollView:(WSWscrollView *)scrollView;
    //@optional
     //點擊事件回調
- (void)wswScroView:(WSWscrollView *)scrollView didSelectRowAtIndexPath:(NSInteger)index;
.
使用這個輪播器,要遵循兩個協議,並且必須實現一個方法:傳入圖片數組.
這裏說明一下,圖片數組不用你來區分本地還是網絡圖片了,老賴幫你判斷了.
本地圖片的話,你就傳入照片名字的數組,別忘了jpg的要在名字後面加上.jpg哦!
網絡圖片的話,就傳網絡圖片地址的字符串就行!
點擊事件回調,會傳過來一個圖片的位置,你拿着這個位置下標,就可以進行其他操作了!
另外這裏還有可調節時間計時器,手動銷燬計時器,和手動開啓計時器的外部接口,方便你自己添加功能或者項目需求吧;

再來說說Block封裝的:

/**
 *  傳入照片,並返回圖片點擊的回調block
 *
 *  @param imagesArray            傳入本地圖片或者網絡圖片
 *  @param currentImageClickBlock 圖片點擊的block方法
 */
- (void)addImagesArray:(NSArray *)imagesArray currentImageClick:(CurrentImageClick)currentImageClickBlock;
.
調用這個方法,傳入圖片源數組,然後手寫回調block方法就可以了,下面是demo中的例子,可以看一眼:
    //調用方法-->就是直接創建一個對象
    WSWscrollView *scrollView = [[WSWscrollView alloc] initWithFrame:self.view.bounds];
    /*
     時間間隔一定要寫在調用下面方法之前,因爲方法裏調用了創建時間控制器,
     之後再設置間隔時間的話,就沒有作用了
     */
    scrollView.timeInterval = 1.f;
    NSArray *array = @[@"火影01",@"火影02",@"火影03",@"火影04",];
    //傳入圖片源數組並且實現回調block方法
    [scrollView addImagesArray:array currentImageClick:^(NSInteger index) {
        NSLog(@"--->我點的這是第%ld張圖片",(long)index);
    }];
    //添加帶父視圖上
    [self.view addSubview:scrollView];
.
哎呦,終於寫完啦,iOS開發自學的課程還得繼續更新,好了,老賴整理資料去了,收工!
封裝好的Demo:https://github.com/wswei99/WSWScrollView
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章