tips
今天項(xiàng)目中用到了輪播的功能,本來(lái)想著去網(wǎng)上找個(gè)第三方的,后來(lái)想一下自己實(shí)現(xiàn)一個(gè)也是挺簡(jiǎn)單的.于是就有了這篇文章
一. 需求分析
總結(jié)了一下,一個(gè)廣告輪播必須含有以下幾個(gè)功能;
- 頁(yè)面內(nèi)容可以自定義;比如說(shuō)可以是圖片輪播,也可以是其他view
- 可以實(shí)現(xiàn)定時(shí)輪播;
- 能處理輪播頁(yè)的點(diǎn)擊事件;
- 滑動(dòng)到最后一頁(yè)的時(shí)候再往下滑動(dòng)可以到第一頁(yè),第一頁(yè)再往回滑動(dòng)可以到最后一頁(yè)
- 最好能封裝成一個(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)張效果圖吧
代碼已上傳github-->Banner