自定义View之无限轮播Banner的实现:STBanner
2016-05-16 15:38
369 查看
去年做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"]; _p cff8 ageControl.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到此结束!睡觉
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 个人信息安全报告发布:有 APP 每分钟调用位置权限 1468 次
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- 下载量超过一亿的流行应用被发现含有恶意模块
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 苹果与Siri的七年之痒:“宫斗”戏码不断上演
- APP添加CNZZ统计插件教程 Android版添加phonegap
- ScrollView滚动条颜色的设置方法
- jquery实现简单的banner轮播效果【实例】
- Android APP与媒体存储服务的交互
- java实现收藏名言语句台词的app
- 刷新Activity中的scrollview示例(局部ui刷新)
- 修改Android App样式风格的方法
- Android App数据格式Json解析方法和常见问题
- JS实现带关闭功能的阿里妈妈网站顶部滑出banner工具条代码
- 讲解iOS开发中基本的定位功能实现