自定义View之无限轮播Banner的实现:STBanner

去年做E4S电商平台APP( PS:平台垮了,没上线,杯具-_-|| )的时候实现了一个Banner,起初没想着要实现循环滚动的效果,后来业务提了个问题,要求首页的banner能够循环轮播,那时我就奈闷了,苹果的scrollview好像是没有循环滚动的吧(PS:那时还是个雏,搞IOS开发没多久),拔光头发还想不出,后来通过网络搜索,爬贴,各种跪拜...最后得出个点子,就是"n+2".

什么是"n+2"呢,其实这个方法有点鸡肋,别看上去名字好像挺高大上的,说到底就是...就是...第一张左边添加最后一张,最后一张右边添加第一张,这就是n+2.很鸡肋吧,原理是很简单,写成代码又是另一回事了,当然这里没有太过复杂的算法,但是如果封装得好,感觉也是成就感满满的,呵呵!大笑

    其实我知道有种方法更好,记得有个设计模式叫享元模式,用这个模式可以让对象的重用性充分利用,这样就能够比较完美了,我想最好的方法应该莫过于此吧...(求大牛莫喷,放过小弟吧,行行好!),但是想到实用性与现实性,必竟banner数量是有限的,所以没必要写太复杂,简单的东西多好!我就喜欢简单的东西,有同感的亲举手啦!得意

    好吧,不说太多废话了,上代码吧(这里可能代码写得不怎样,但为了照顾新手,也为了自已进步,所以放大码了,让大家批斗吧).

首先是STBanner.h文件,应该不用说都看得懂吧...

#import <UIKit/UIKit.h>


/** 点击回调*/

typedef void (^onSelectBlock) (NSInteger selectedIndex);




@interface STBanner : UIView 



/**

 * 初始化STBanner

 *

 * @param bannerArr 图片地址数组

 * @param frame 位置大小

 * @return STBanner

 */

+ (instancetype)bannerWithBannerArray:(NSArray *)bannerArr withFrame:(CGRect)frame onSelectBlock:(onSelectBlock)block;



/**

 *销毁方法

 */

- (void)dead;


@end



然后是STBanner.m文件,这里引用了文件STPageControl.h这个类(这个后面补上),还有SDImage这个类库

 //*   本循环滚动视图是  n+2原理 实现的

 //*   简单来说就是  :   第一张左边添加最后一张,最后一张右边添加第一张,这就是n+2



#import "STBanner.h"

#import "STPageControl.h"

#import "UIImageView+WebCache.h"


#define TIMER_DURACTION 4.0f

#define kIsOutOfRange



@interface STBanner() <UIScrollViewDelegate>


/** 子滚动视图*/

@property (nonatomic, strong) UIScrollView *scrollview;

/** 页面指示器*/

@property (nonatomic, strong) UIPageControl * pageControl;



/** 图片地址数组*/

@property (nonatomic, strong) NSArray *bannerArr;

/** 图片容器*/

@property (nonatomic, strong) NSMutableArray * containers;



/** 页数(n+2后的页数,并非实际显示的页数)*/

@property (nonatomic, assign) int pageCount;

/** 是否手动拖动*/

@property (nonatomic, assign) BOOL isDragging;



/** 计时器*/

@property (nonatomic, strong) NSTimer *timer;



/** 点击图片的回调*/

@property (nonatomic, strong) onSelectBlock block;



@end



@implementation STBanner


#pragma mark - Initialize

- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];

    NSAssert(self, @"STBanner实例化错误");

    [self commonInit];

    

    return self;

}


- (void)commonInit {

    [self addSubview:self.scrollview];

    [self addSubview:self.pageControl];

    

    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]

                                    initWithTarget:self

                                    action:@selector(bannerTap)];

    [self addGestureRecognizer:tap];

    self.userInteractionEnabled = YES;

}


+ (instancetype)bannerWithBannerArray:(NSArray *)bannerArr withFrame:(CGRect)frame onSelectBlock:(onSelectBlock)block

{

    STBanner * banner = [[STBanner alloc]initWithFrame:frame];

    banner.bannerArr = bannerArr?[NSArray arrayWithArray:bannerArr]:nil ;

    banner.pageCount = (int)bannerArr.count+2;

    banner.containers = [NSMutableArray array];

    banner.block = block;

    

    banner.scrollview.contentSize =

    CGSizeMake((frame.size.width * bannerArr.count) + (2 * frame.size.width), 0);

    banner.scrollview.contentOffset =

    CGPointMake(banner.frame.size.width, 0);

    [banner.scrollview setScrollEnabled:bannerArr.count-1];

    

    [banner createContainers];

    bannerArr.count - 1 ? [banner.timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:TIMER_DURACTION]]:NULL;

    

    banner.pageControl.numberOfPages = banner.bannerArr.count ;

    

    return banner;

}



- (void)createContainers {

    //初始化图片容器

    for (NSInteger i = 0; i < self.pageCount; i ++) {

        UIImageView * iv    = [[UIImageView alloc]initWithFrame:

                               CGRectMake(self.frame.size.width * i,

                                          self.frame.origin.y,

                                          self.frame.size.width,

                                          self.frame.size.height)];

        

        [iv setBackgroundColor:[UIColor colorWithWhite:1.f alpha:.5f]];

        

        [self.scrollview addSubview:iv];

        [self.containers addObject:iv];

        

        /** 图片的加载*/

        NSInteger index;

        if ((i != self.pageCount - 1) && i)

        {//除第一张和最后一张,都按顺序加载图片

            index = i-1;

        }

        else

        {

            if (i == self.pageCount-1)

            {//最后一张用来显示第一图片

                index = 0;

            }

            else if(!i)

            {//第一张用来显示最后一张图片

                index = self.bannerArr.count-1;

            }

        }

        [iv sd_setImageWithURL:[NSURL URLWithString:self.bannerArr[index]] placeholderImage:nil];

    }

}


- (void)layoutSubviews {

    [super layoutSubviews];

    self.scrollview.frame = self.frame;

    self.pageControl.frame = CGRectMake(self.frame.origin.x,

                                        self.frame.size.height-37,

                                        self.frame.size.width,

                                        37);

}



#pragma mark - Getters

- (UIScrollView *)scrollview {

    if (!_scrollview) {

        _scrollview = [[UIScrollView alloc]init];

        _scrollview.delegate = self;

        _scrollview.pagingEnabled = YES ;

        _scrollview.showsHorizontalScrollIndicator = NO ;

        _scrollview.backgroundColor = [UIColor clearColor];

        

    }

    return _scrollview;

}


- (UIPageControl *)pageControl {

    if (!_pageControl) {

        _pageControl = [[STPageControl alloc]

                        initWithPageIndicatorImageName:@"pagecontrol-thumb-normal"

                        withCurrentPageIndicatorImageName:@"pagecontrol-thumb-selected"];

        _pageControl.pageIndicatorTintColor = [UIColor clearColor];

        _pageControl.currentPageIndicatorTintColor = [UIColor clearColor];

        _pageControl.userInteractionEnabled = NO ;

        

    }

    return _pageControl;

}


- (NSMutableArray *)containers{

    if (!_containers) {

        _containers = [NSMutableArray arrayWithCapacity:0];

    }

    return _containers;

}


- (NSTimer *)timer{

    if (!_timer) {

        _timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_DURACTION target:self selector:@selector(changePict) userInfo:nil repeats:YES];

        [_timer setFireDate:[NSDate distantFuture]];

    }

    return _timer;

}





#pragma mark - UIScrollViewDelegate

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

    

    CGFloat x = scrollView.contentOffset.x ;

    NSInteger index = round(x/[UIScreen mainScreen].bounds.size.width)-1;

    self.pageControl.currentPage = index ;

    

    // 判断是否手动控制(isTimeUp NO 为手动)

    _isDragging?[_timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:TIMER_DURACTION]]:NULL;

    

    if (x > self.scrollview.contentSize.width - self.frame.size.width)

    {

        [self scrollToFirst];

    }

    else if(x <= 0)

    {

        [self scrollToLast];

    }

    

}


-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {

    _isDragging = YES;

}


-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

    _isDragging = NO;

    CGFloat x = scrollView.contentOffset.x ;

    if (x > self.scrollview.contentSize.width - self.frame.size.width * 2)

    {

        

        [self scrollToFirst];

        

    }else if(x == 0)

    {

        

        [self scrollToLast];

        

    }

}


/** 轮播动画*/

-(void)changePict {

    CGFloat x = self.scrollview.contentOffset.x + self.frame.size.width;

    [UIView animateKeyframesWithDuration:0.5 delay:0 options:UIViewKeyframeAnimationOptionAllowUserInteraction animations:^ {

        [self.scrollview setContentOffset:CGPointMake(x, 0)];

        if (x > self.scrollview.contentSize.width - self.frame.size.width * 2)

        {

            self.pageControl.currentPage = 0;

        }

    } completion:^(BOOL finished) {

        if (x > self.scrollview.contentSize.width - self.frame.size.width * 2)

        {

            [self scrollToFirst];

            

        }

    }];

}


/** 跳到第一张图片*/

- (void)scrollToFirst{

    [self.scrollview setContentOffset:CGPointMake(self.frame.size.width, 0)];

}


/** 跳到最后一张图片*/

- (void)scrollToLast{

    [self.scrollview setContentOffset:CGPointMake(self.frame.size.width*self.bannerArr.count,0 )];

}





#pragma mark - Actions

-(void)bannerTap {

    

    self.block&&self.bannerArr.count?

    self.block(self.pageControl.currentPage):NULL;

    

}



- (void)dead {

    [_pageControl removeFromSuperview];

    [_timer invalidate];

    [self removeFromSuperview];

}



然后这里补上STPageControl.h

#import <UIKit/UIKit.h>


@interface STPageControl : UIPageControl


/**

 * 初始化STPageControl

 *

 * @param pageIndicatorImageName

 * @param currentPageIndicatorImageName

 * @return STPageControl

 */

- (instancetype)initWithPageIndicatorImageName:(NSString *)pageIndicatorImageName withCurrentPageIndicatorImageName:(NSString *)currentPageIndicatorImageName;



@end


STPageControl.m

#import "STPageControl.h"


@interface STPageControl (){

    UIImage * _activeImage;

    UIImage *_inactiveImage;

}

@property (nonatomic ,strong) UIImage *activeImage;

@property (nonatomic, strong) UIImage *inactiveImage;

@end


@implementation STPageControl


#pragma mark - Initialize 

- (instancetype)initWithPageIndicatorImageName:(NSString *)pageIndicatorImageName withCurrentPageIndicatorImageName:(NSString *)currentPageIndicatorImageName{

    

    NSAssert(self = [super init], @"STPageControl初始化错误!");

    _activeImage = [UIImage imageNamed:currentPageIndicatorImageName];

    _inactiveImage = [UIImage imageNamed:pageIndicatorImageName];

    

    return self;

}



#pragma mark - Setters

- (void)setCurrentPage:(NSInteger)currentPage

{

    [super setCurrentPage:currentPage];

    [self updateDots];

}


/** 替换pageControl小点*/

- (void)updateDots

{

    for (int i = 0; i< [self.subviews count]; i++)

    {

        UIView *view = [self.subviews objectAtIndex:i];

        CGRect frame = view.frame;

        view.backgroundColor = [UIColor clearColor];

        frame.size.width = 6.0f;

        frame.size.height = 6.0f;

        view.layer.cornerRadius = 0.0f;

        view.frame = frame;

        

        if (!view.subviews.count) {

            UIImageView *iv = [[UIImageView alloc]initWithFrame:CGRectMake(0,

                                                                           0,

                                                                           frame.size.width,

                                                                           frame.size.height)];

            [view addSubview:iv];

        }

        

        

        UIImageView  *iv = [view.subviews firstObject];

        if (i == self.currentPage)

        {

            [iv setImage:self.activeImage];

        }

        else

        {

            [iv setImage:self.inactiveImage];

        }

        

    }

}


最后写上ViewController里的调用例子(很简单,也许是我写得好吧!安静自嘲一下哈)

好,附上ViewController.m文件内容

#import "ViewController.h"

#import "STBanner.h"


@interface ViewController ()


@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    NSArray *dataArray = @[

                           @"http://pic26.nipic.com/20130121/9475856_141716386357_2.jpg",

                           @"http://pic23.nipic.com/20120823/6854834_144345077352_2.jpg",

                           @"http://pic30.nipic.com/20130626/12977223_211915153000_2.jpg",

                           @"http://pic12.nipic.com/20110124/5375473_153252019000_2.jpg"

                           ];


    [self.view addSubview:[STBanner bannerWithBannerArray:dataArray

                                                withFrame:CGRectMake(0,

                                                                     0,

                                                                     self.view.frame.size.width,

                                                                     self.view.frame.size.width * .33f)

                                            onSelectBlock:^(NSInteger selectedIndex)

    {

        NSLog(@"%ld",selectedIndex);

        [self showAlertWithMessage:[NSString stringWithFormat:@"%@",@(selectedIndex)]];

    }]];

    

    // Do any additional setup after loading the view, typically from a nib.

}


- (void)showAlertWithMessage:(NSString *)message {

    [[[UIAlertView alloc]initWithTitle:nil message:message delegate:nil cancelButtonTitle:@"oklala" otherButtonTitles: nil]show];

}



- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


@end


好了,代码到此结束,吐cao到此结束!睡觉



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值