利用UIPageViewController實(shí)現(xiàn)圖片輪播(簡(jiǎn)單實(shí)用版本)

tips

今天項(xiàng)目中用到了輪播的功能,本來(lái)想著去網(wǎng)上找個(gè)第三方的,后來(lái)想一下自己實(shí)現(xiàn)一個(gè)也是挺簡(jiǎn)單的.于是就有了這篇文章

一. 需求分析

總結(jié)了一下,一個(gè)廣告輪播必須含有以下幾個(gè)功能;

  1. 頁(yè)面內(nèi)容可以自定義;比如說(shuō)可以是圖片輪播,也可以是其他view
  2. 可以實(shí)現(xiàn)定時(shí)輪播;
  3. 能處理輪播頁(yè)的點(diǎn)擊事件;
  4. 滑動(dòng)到最后一頁(yè)的時(shí)候再往下滑動(dòng)可以到第一頁(yè),第一頁(yè)再往回滑動(dòng)可以到最后一頁(yè)
  5. 最好能封裝成一個(gè)view,便于日后的使用

確定好要實(shí)現(xiàn)的功能,又到了我們最開(kāi)心的編碼環(huán)節(jié).

二. 需求設(shè)計(jì)

本來(lái)我第一時(shí)間想到的是利用UiScrollview或者UiCollectionView等組件來(lái)實(shí)現(xiàn),不過(guò)在以前一篇仿今日頭條新聞分頁(yè)中文章中我講過(guò)一下他們和UIPageViewController的區(qū)別.所以今天我就選定UIPageViewController來(lái)當(dāng)我們這次的主角啦!

代碼實(shí)現(xiàn)

我們新建一個(gè)BannerView的自定義view,所有的邏輯代碼就寫里面啦.

1.首先我們確定一下需要的一些變量屬性,具體詳情看注釋就明白了(小編代碼注釋寫的賊多)
@property (nonatomic,strong)UIPageViewController *pageCon;
/**
 指示器
 */
@property (nonatomic,strong)UIPageControl *indicator;
/**
 存放所有的圖片地址
 */
@property (nonatomic,strong)NSArray *imageArr;

/**
 存放所有的頁(yè)面
 */
@property (nonatomic,strong)NSMutableArray *controlls;
/**
 當(dāng)前tag值
 */
@property (nonatomic,assign)NSInteger tagIndex;
/**
 輪播定時(shí)器
 */
@property (nonatomic,strong)NSTimer *timeZ;
/**
 回調(diào)點(diǎn)擊的圖片所在的tag值
 */
@property (nonatomic,strong)bannerResult block;
/**
 是否在自動(dòng)輪播
 */
@property (nonatomic,assign)BOOL isAuto;
2. 初始化我們需要的相關(guān)view和一下相關(guān)變量
-(instancetype)initWithFrame:(CGRect)frame{
    self=[super initWithFrame:frame];
    if(self){
        [self initView];
        
    }
    return self;
    
}

-(void)initView{
    _controlls=[[NSMutableArray alloc]init];
    _tagIndex=0;//默認(rèn)tag==0
    _pageCon=[[UIPageViewController alloc]initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
    _pageCon.delegate = self;
    _pageCon.dataSource = self;
    _pageCon.view.frame=self.bounds;
    [self addSubview:_pageCon.view];
    
    _indicator=[[UIPageControl alloc]init];

    [self addSubview:_indicator];

    //這里用了Masonry框架代碼,就是底部居中的意思,不想用該框架的可以用其他的約束
    [_indicator mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(self);
        make.bottom.equalTo(self.mas_bottom).offset(10);
    }];
}
3. 初始化一些頁(yè)面數(shù)據(jù)

主要是創(chuàng)建輪播頁(yè)以及輪播頁(yè)面里面要添加的內(nèi)容(這里我們只要放一個(gè)圖片即可)

-(void)initData:(NSArray *)arr block:(bannerResult)block{
    _isAuto=false;
    _block=block;
    _imageArr=arr;
    _indicator.numberOfPages=_imageArr.count;

    [_imageArr enumerateObjectsUsingBlock:^(NSString* obj, NSUInteger idx, BOOL * _Nonnull stop) {
        //創(chuàng)建輪播頁(yè)
        UIViewController *con=[[UIViewController alloc]init];
        con.view.frame=self.bounds;
        UIImageView *image=[[UIImageView alloc]initWithFrame:self.bounds];
        image.contentMode=UIViewContentModeScaleAspectFill;
         [image sd_setImageWithURL:[NSURL URLWithString:obj]];
        [con.view addSubview:image];
        [_controlls addObject:con];
        
        [self setListener:con.view index:idx];  //這是設(shè)置每個(gè)頁(yè)面點(diǎn)擊事件的方法,
    }];
    
     [_pageCon setViewControllers:[NSArray arrayWithObject:[self pageControllerAtIndex:_tagIndex]] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
    
}
4. 添加UIPageViewController代理

這里我們要注意兩點(diǎn):
1.開(kāi)始滑動(dòng)和結(jié)束滑動(dòng)時(shí)的事件,當(dāng)開(kāi)始滑動(dòng)的時(shí)候,我們?nèi)绻O(shè)置了自動(dòng)輪播,就要先停止輪播,優(yōu)先響應(yīng)滑動(dòng)事件,防止出現(xiàn)滑動(dòng)和輪播沖突問(wèn)題.
2.當(dāng)滑到最后一頁(yè)的時(shí)候,我們的代理方法中要給出第0頁(yè)當(dāng)成下一頁(yè),當(dāng)滑到第一頁(yè)再往回滑動(dòng)的時(shí)候,我們要將最后一頁(yè)當(dāng)成上一頁(yè),這樣就做到了循環(huán)滑動(dòng)了.

//返回下一個(gè)頁(yè)面
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController{
    
    NSInteger index= [_controlls indexOfObject:viewController];
    NSLog(@"viewControllerAfterViewController-->%lu",index);

    if(index==(_imageArr.count-1)){
        index=0;
    }else{
        index++;

    }
    return [self pageControllerAtIndex:index];
}
//返回前一個(gè)頁(yè)面
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController{
    //判斷當(dāng)前這個(gè)頁(yè)面是第幾個(gè)頁(yè)面
    NSInteger index=[_controlls indexOfObject:viewController];
    NSLog(@"viewControllerBeforeViewController-->%lu",index);
    //如果是第一個(gè)頁(yè)面
    if(index==0){
        index=_imageArr.count-1;
        
    }else{
        index--;

    }
    return [self pageControllerAtIndex:index];
    
}

//根據(jù)tag取出內(nèi)容頁(yè)面
-(UIViewController*)pageControllerAtIndex:(NSInteger)index{
    if(_controlls!=nil&&_controlls.count!=0){
        UIViewController *con=_controlls[index];
        return con;
    }
    return nil;
}
//結(jié)束滑動(dòng)的時(shí)候觸發(fā)
-(void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers transitionCompleted:(BOOL)completed{
    
    NSInteger index=[_controlls indexOfObject:pageViewController.viewControllers[0]];
     _tagIndex=index;
    [_indicator setCurrentPage:_tagIndex];
    if(isAuto){//判斷輪播是否開(kāi)啟,如果已開(kāi)啟,重新啟動(dòng)定時(shí)器
        [self openAuto];

    }
}
//開(kāi)始滑動(dòng)的時(shí)候觸發(fā)
-(void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers{
    [self closeAuto];
}




5. 定時(shí)器的方法

為了方便對(duì)外部調(diào)用,提供了開(kāi)啟和關(guān)閉定時(shí)器的兩個(gè)方法

//開(kāi)啟定時(shí)器
-(void)openAuto{
    
    _isAuto=true;
    
    //開(kāi)啟自動(dòng)輪播
    ALWk(weakSelf);
    _timeZ=[NSTimer scheduledTimerWithTimeInterval:5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"定時(shí)切換--%lu",_tagIndex);
        weakSelf.tagIndex++;
        if(weakSelf.tagIndex>(weakSelf.imageArr.count-1)){
            weakSelf.tagIndex=0;
        }
        
        [_indicator setCurrentPage:weakSelf.tagIndex];
        [weakSelf.pageCon setViewControllers:[NSArray arrayWithObject:[weakSelf pageControllerAtIndex:weakSelf.tagIndex]] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
      
    }];
}
//關(guān)閉定時(shí)器
-(void)closeAuto{
    if(_timeZ){
        _isAuto=false;

        [_timeZ invalidate];
        _timeZ=nil;
    }
    
}

至此,我們的核心代碼就寫完了,接下來(lái)我們只需要隨便在個(gè)控制器中引入bannerView即可

三. 測(cè)試效果

先來(lái)張效果圖吧

image

代碼已上傳github-->Banner

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末娜膘,一起剝皮案震驚了整個(gè)濱河市游添,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌俱饿,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件低零,死亡現(xiàn)場(chǎng)離奇詭異副硅,居然都是意外死亡瘩欺,警方通過(guò)查閱死者的電腦和手機(jī)嚷炉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門轻黑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撤蟆,“玉大人嬉探,你說(shuō)我怎么就攤上這事庙洼∽罾伲” “怎么了碳蛋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵钧忽,是天一觀的道長(zhǎng)毯炮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)惰瓜,這世上最難降的妖魔是什么否副? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮崎坊,結(jié)果婚禮上备禀,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好曲尸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布赋续。 她就那樣靜靜地躺著,像睡著了一般另患。 火紅的嫁衣襯著肌膚如雪纽乱。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天昆箕,我揣著相機(jī)與錄音鸦列,去河邊找鬼。 笑死鹏倘,一個(gè)胖子當(dāng)著我的面吹牛薯嗤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纤泵,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼骆姐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了捏题?” 一聲冷哼從身側(cè)響起玻褪,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎公荧,沒(méi)想到半個(gè)月后带射,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡稚矿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年庸诱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晤揣。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桥爽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昧识,到底是詐尸還是另有隱情钠四,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布跪楞,位于F島的核電站缀去,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏甸祭。R本人自食惡果不足惜缕碎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望池户。 院中可真熱鬧咏雌,春花似錦凡怎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至氛雪,卻和暖如春房匆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背报亩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工浴鸿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捆昏。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓赚楚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親骗卜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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