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

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

什么是”n+2”呢,其实这个方法有点鸡肋,别看上去名字好像挺高大上的,说到底就是…就是…第一张左边添加最后一张,最后一张右边添加第一张,这就是n+2.很鸡肋吧,原理是很简单,写成代码又是另一回事了,当然这里没有太过复杂的算法,但是如果封装得好,感觉也是成就感满满的,呵呵!大笑
其实我知道有种方法更好,记得有个设计模式叫享元模式,用这个模式可以让对象的重用性充分利用,这样就能够比较完美了,我想最好的方法应该莫过于此吧…(求大牛莫喷,放过小弟吧,行行好!),但是想到实用性与现实性,必竟banner数量是有限的,所以没必要写太复杂,简单的东西多好!我就喜欢简单的东西,有同感的亲举手啦!得意
好吧,不说太多废话了,上代码吧(这里可能代码写得不怎样,但为了照顾新手,也为了自已进步,所以放大码了,让大家批斗吧).

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

#import <UIKit/UIKit.h>

/** 点击回调*/
typedefvoid (^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 = [superinitWithFrame:frame];
    NSAssert(self,@"STBanner实例化错误");
    [selfcommonInit];

    return self;
}

- (void)commonInit {
    [selfaddSubview:self.scrollview];
    [selfaddSubview:self.pageControl];

    UITapGestureRecognizer * tap = [[UITapGestureRecognizeralloc]
                                   initWithTarget:self
                                   action:@selector(bannerTap)];
    [selfaddGestureRecognizer:tap];
    self.userInteractionEnabled =YES;
}

+ (instancetype)bannerWithBannerArray:(NSArray *)bannerArr withFrame:(CGRect)frame onSelectBlock:(onSelectBlock)block
{
   STBanner * banner = [[STBanneralloc]initWithFrame:frame];
    banner.bannerArr = bannerArr?[NSArrayarrayWithArray:bannerArr]:nil ;
    banner.pageCount = (int)bannerArr.count+2;
    banner.containers = [NSMutableArrayarray];
    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.scrollviewsetScrollEnabled:bannerArr.count-1];

    [banner createContainers];
    bannerArr.count -1 ? [banner.timersetFireDate:[NSDatedateWithTimeIntervalSinceNow:TIMER_DURACTION]]:NULL;

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

   return banner;
}


- (void)createContainers {
    //初始化图片容器
   for (NSInteger i =0; i < self.pageCount; i ++) {
       UIImageView * iv    = [[UIImageViewalloc]initWithFrame:
                              CGRectMake(self.frame.size.width * i,
                                         self.frame.origin.y,
                                         self.frame.size.width,
                                         self.frame.size.height)];

        [iv setBackgroundColor:[UIColorcolorWithWhite:1.falpha:.5f]];

        [self.scrollviewaddSubview:iv];
        [self.containersaddObject: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:[NSURLURLWithString:self.bannerArr[index]]placeholderImage:nil];
    }
}

- (void)layoutSubviews {
    [superlayoutSubviews];
   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 = [[UIScrollViewalloc]init];
       _scrollview.delegate =self;
       _scrollview.pagingEnabled =YES ;
        _scrollview.showsHorizontalScrollIndicator =NO ;
        _scrollview.backgroundColor = [UIColorclearColor];

    }
    return_scrollview;
}

- (UIPageControl *)pageControl {
    if (!_pageControl) {
        _pageControl = [[STPageControlalloc]
                        initWithPageIndicatorImageName:@"pagecontrol-thumb-normal"
                        withCurrentPageIndicatorImageName:@"pagecontrol-thumb-selected"];
        _pageControl.pageIndicatorTintColor = [UIColorclearColor];
        _pageControl.currentPageIndicatorTintColor = [UIColorclearColor];
        _pageControl.userInteractionEnabled =NO ;

    }
    return_pageControl;
}

- (NSMutableArray *)containers{
    if (!_containers) {
        _containers = [NSMutableArrayarrayWithCapacity:0];
    }
    return_containers;
}

- (NSTimer *)timer{
   if (!_timer) {
        _timer = [NSTimerscheduledTimerWithTimeInterval:TIMER_DURACTIONtarget:selfselector:@selector(changePict)userInfo:nilrepeats:YES];
        [_timersetFireDate:[NSDatedistantFuture]];
    }
   return _timer;
}




#pragma mark - UIScrollViewDelegate
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {

   CGFloat x = scrollView.contentOffset.x ;
    NSInteger index =round(x/[UIScreenmainScreen].bounds.size.width)-1;
   self.pageControl.currentPage = index ;

    // 判断是否手动控制(isTimeUp 的 NO 值 为手动)
    _isDragging?[_timersetFireDate:[NSDatedateWithTimeIntervalSinceNow:TIMER_DURACTION]]:NULL;

    if (x >self.scrollview.contentSize.width -self.frame.size.width)
    {
        [selfscrollToFirst];
    }
   else if(x <=0)
    {
        [selfscrollToLast];
    }

}

-(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)
    {

        [selfscrollToFirst];

    }elseif(x == 0)
    {

        [selfscrollToLast];

    }
}

/** 轮播动画*/
-(void)changePict {
    CGFloat x = self.scrollview.contentOffset.x +self.frame.size.width;
    [UIViewanimateKeyframesWithDuration:0.5delay:0options:UIViewKeyframeAnimationOptionAllowUserInteractionanimations:^ {
        [self.scrollviewsetContentOffset: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)
        {
            [selfscrollToFirst];

        }
    }];
}

/** 跳到第一张图片*/
- (void)scrollToFirst{
    [self.scrollviewsetContentOffset:CGPointMake(self.frame.size.width,0)];
}

/** 跳到最后一张图片*/
- (void)scrollToLast{
    [self.scrollviewsetContentOffset: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 {
    [_pageControlremoveFromSuperview];
    [_timerinvalidate];
    [selfremoveFromSuperview];
}

然后这里补上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 = [superinit], @"STPageControl初始化错误!");
   _activeImage = [UIImageimageNamed:currentPageIndicatorImageName];
   _inactiveImage = [UIImageimageNamed:pageIndicatorImageName];

    return self;
}


#pragma mark - Setters
- (void)setCurrentPage:(NSInteger)currentPage
{
    [supersetCurrentPage:currentPage];
    [selfupdateDots];
}

/** 替换pageControl小点*/
- (void)updateDots
{
   for (int i =0; i< [self.subviewscount]; i++)
    {
       UIView *view = [self.subviewsobjectAtIndex:i];
       CGRect frame = view.frame;
        view.backgroundColor = [UIColorclearColor];
        frame.size.width =6.0f;
        frame.size.height =6.0f;
        view.layer.cornerRadius =0.0f;
        view.frame = frame;

       if (!view.subviews.count) {
            UIImageView *iv = [[UIImageViewalloc]initWithFrame:CGRectMake(0,
                                                                          0,
                                                                           frame.size.width,
                                                                           frame.size.height)];
            [viewaddSubview:iv];
        }


       UIImageView  *iv = [view.subviewsfirstObject];
       if (i == self.currentPage)
        {
            [ivsetImage:self.activeImage];
        }
       else
        {
            [ivsetImage:self.inactiveImage];
        }

    }
}

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

#import "ViewController.h"
#import "STBanner.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [superviewDidLoad];
   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.viewaddSubview:[STBannerbannerWithBannerArray:dataArray
                                               withFrame:CGRectMake(0,
                                                                    0,
                                                                    self.view.frame.size.width,
                                                                    self.view.frame.size.width *.33f)
                                           onSelectBlock:^(NSInteger selectedIndex)
    {
       NSLog(@"%ld",selectedIndex);
        [selfshowAlertWithMessage:[NSStringstringWithFormat:@"%@",@(selectedIndex)]];
    }]];

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

- (void)showAlertWithMessage:(NSString *)message {
    [[[UIAlertViewalloc]initWithTitle:nilmessage:message delegate:nilcancelButtonTitle:@"oklala"otherButtonTitles: nil]show];
}

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值