UI 一一 手把手教你封装一个广告轮播图框架
来源:互联网 发布:c语言实现arp欺骗 编辑:程序博客网 时间:2024/05/16 07:19
前言
广告轮播图如今早已是iOS应用的标配了,似乎任何一款App的首页都会有一个广告轮播图。
本文的目的就是要将App里面的广告轮播图封装成一个独立模块,以便简化开发过程。
如果你对独立“封装一个自己的广告轮播图”感兴趣,欢迎继续读下去。
轮播图效果
为了从开始讲述整个动手封装轮播图的过程,我们先从简单的开始,后期我会一步步把功能封装的更加完善起来,欢迎去我的github上去下载完整代码,如果有什么问题更欢迎随时issue我。
轮播图分析
当我们做一个很独立的功能时候可能会感觉内部功能较多而感觉无从下手,下面我们就先分析一下这个轮播图主要部件。
轮播图“原料”
- UIScrollView
- UIPageControl
- UIImageView
思路
- 图片放到ScrollView上水平排列
- 放置小圆点(pageControl)标识位置
- 开启定时滚动功能
有了小的思路,那就开始一点点做,(这里只是简单思路,做的过程中会根据遇到的问题一点点改善)
创建基本组件
先把基本的框架和布局搭建起来
- 创建基本可滚动广告图
- 添加PageControl
这一步需要添加页面控制,标识是哪个展示图片的位置
不过在加入之前,先引入一个封装思想
封装思想
到这里就出现了一个问题,我们的功能和内容在变多,如果还像刚才这个ScrollView一样直接拖过去使用的话虽然没有问题,但是想改变整个控件位置,或者给他人使用等等的情况下就会非常麻烦,需要改动太多东西。
所以我们需要将整个控件封装起来,把里面的东西放到控件内部,以降低“轮播图”和这个项目的耦合性,增加可复用性。详解请参考iOS回顾笔记(03)
我们可以从用户的角度去考虑如何使用
用户使用应该以简单为主,这样简单设置就能用最好。至于内部实现才是我们要关心的 // 1.创建banner XYBannerView *banner = [XYBannerView bannerView]; // 2.设置banner相关属性 banner.imagesArr = @[@"img_00",@"img_01",@"img_02",@"img_03",@"img_04"]; banner.frame = CGRectMake(37.5, 100, 300, 150); // 3.添加到UI上 [self.view addSubview:banner];
新建BannerView文件
- 新建文件,此步用xib快速实现布局scrollView和pageControl
设计BannerView.h接口文件
接口文件就是用户使用BannerView时候查看参数和方法用的,有什么功能和参数要写清楚,
以现在这个为例
// 要展示图片数组@property (nonatomic, strong) NSArray *imagesArr;// 返回一个实例的方法+ (instancetype)bannerView;
根据外界调用来实现BannerView.m 的内部功能
这个BannerView的主要功能是动态轮播广告图,所以要重写imageArr的set方法
- (void)setImagesArr:(NSArray *)imagesArr{ _imagesArr = imagesArr; // 创建对应的imageView添加到scrollView中去 for (int i = 0 ; i < imagesArr.count ;i++) { // 根据位置index创建图片 NSString *imageName = [NSString stringWithFormat:@"img_0%d",i]; UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]]; imageView.frame = CGRectMake(i * imageView.frame.size.width, 0, imageView.frame.size.width, self.scrollView.frame.size.height); // 添加到ScrollView上 [self.scrollView addSubview:imageView]; } self.scrollView.contentSize = CGSizeMake(imagesArr.count * self.scrollView.frame.size.width, 0); self.scrollView.pagingEnabled = YES; // 关于pageControll的设置 self.pageControll.numberOfPages = imagesArr.count; self.pageControll.currentPage = 1; self.pageControll.currentPageIndicatorTintColor = [UIColor yellowColor]; self.pageControll.pageIndicatorTintColor = [UIColor grayColor];}
设置pageControll监听当前页面
pageControll就是这个小圆点,用来标识轮播页面的当前页
这里主要通过设置ScrollView的代理来监听当前页面,通过修改pageControll的当前页来达成一致。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ // 实时监听当前第几页,根据当前偏移量来 self.pageControll.currentPage = (int)(self.scrollView.contentOffset.x / self.scrollView.frame.size.width + 0.5);}
- 设置定时器,让图片自动滚起来
定时器:NSTimer 就是一个可以设置定时功能的系统组件。
// 创建定时器,设置每1.5秒进行 跳转下一页的功能self.timer = [NSTimer scheduledTimerWithTimeInterval:1.5 repeats:YES block:^(NSTimer * _Nonnull timer) { [self nextPage]; }];// 启动定时器 [self.timer fire];
[self nextPage]方法的具体实现
// 获取当前页数 NSInteger page = self.pageControll.currentPage + 1; if (page == self.pageControll.numberOfPages) { page = 0; } // 设置滚动动画 [UIView animateWithDuration:0.5 animations:^{ //每次滚动就是,改变对应偏移量 CGPoint offsize = self.scrollView.contentOffset; offsize.x = page * self.scrollView.frame.size.width; self.scrollView.contentOffset = offsize; }];
到这里一个简单的广告轮播就做完了
这个小轮播图马马虎虎也可以用了,但是还存在着一些严重的问题,下面来解决问题。
存在的问题
性能问题
- 从设计逻辑来看,这个图片轮播是直接创建了与图片相等的ImageView来进行轮播的。
- 如果直接传100张图片,同时创建100个imageView是很浪费内存的,并且用户还不一定会看
线程问题
- 用户拖拽图片的时候会造成轮播当时停下来,手一松又会快速的轮播
- 用户处理其他时间的时候,如底部有文本框编辑文字,轮播图会停止轮播
问题的解决
性能问题
为提升性能,我们应该复用对应的imageView,而不是一次创建那么多
具体做法就是,固定创建对应的ImageView,每次给iamges赋值的时候进行判断当前是第几张图片,是第几页。ImageView在轮播的过程中要通过计算切换图片和页码。
#pragma mark - 重写set方法- (void)setImagesArr:(NSArray *)imagesArr{ _imagesArr = imagesArr; // 设置内容 [self setupContent]; // 设置 self.pageControll.numberOfPages = imagesArr.count; self.pageControll.currentPage = 0; // 设置定时功能 [self startTimer];}- (void)setupContent{ // 设置图片,页码(这是一个循环,自己演算一下即可) for (int i = 0; i < self.scrollView.subviews.count; i++) { UIImageView *imageView = self.scrollView.subviews[i]; NSInteger index = self.pageControll.currentPage; if (i == 0) { index--; } else if (i == 2) { index++; } if (index < 0) { index = self.pageControll.numberOfPages - 1; } else if (index >= self.pageControll.numberOfPages) { index = 0; } imageView.tag = index; imageView.image = [UIImage imageNamed:self.imagesArr[index]]; } // 设置当前偏移量 self.scrollView.contentOffset = CGPointMake(self.scrollView.frame.size.width, 0);}#pragma mark - 代理监听页面滚动// 滚动的时候定位当前正确的页数- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ // 找出最中间的那个图片控件 NSInteger page = 0; CGFloat minDistance = MAXFLOAT; for (int i = 0; i<self.scrollView.subviews.count; i++) { UIImageView *imageView = self.scrollView.subviews[i]; CGFloat distance = 0; distance = ABS(imageView.frame.origin.x - scrollView.contentOffset.x); if (distance < minDistance) { minDistance = distance; page = imageView.tag; } } self.pageControll.currentPage = page;}- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ [self setupContent];}- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{ [self setupContent];}
- 线程问题
- 这个原因是:NSTimer 默认是放到系统的主线程的,当用户操作其他主线程任务时,会造成NSTimer的线程阻塞,用户停止其他操作时又会重启NSTimer
// 添加定时器- (void)startTimer{ self.timer = [NSTimer scheduledTimerWithTimeInterval:1.5 repeats:YES block:^(NSTimer * _Nonnull timer) { [self nextPage]; }]; // 设置timer在运行循环中模式为 [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];}// 开始滚动的时候停止定时器- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ [self endTimer];}//滚动停止的时候开启定时器- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ [self startTimer];}
到此完美的解决了上述两个问题,如果项目需求不是很复杂,这个已经完全够用了。
小结
广告轮播的Demo基本做完了,并且修复和完善了性能和体验上的问题。
简单项目中已经基本可用了。具体使用方法
导入框架后: // 1.创建banner XYBannerView *banner = [XYBannerView bannerView]; // 2.设置banner相关属性 banner.imagesArr = @[@"img_00",@"img_01",@"img_02",@"img_03",@"img_04"]; banner.frame = CGRectMake(37.5, 100, 300, 150); // 3.添加到UI上 [self.view addSubview:banner];
- UI 一一 手把手教你封装一个广告轮播图框架
- iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架
- iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架
- iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架
- iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架
- iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架
- iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架
- 轮播图框架
- 轮播图框架
- js轮播图框架结构
- 手把手教你封装一个vue component
- 手把手教你封装一个vue component
- 手把手教你实现一个无限循环的轮播控件
- 封装一个轮播
- android 广告轮播小圆点封装
- 手把手教你用ViewPager自定义实现Banner轮播
- 迅雷官方手把手教你,一个下载软件中到底可以强行植入多少广告
- 简单实用的轮播图框架(导入包以github最新为准)
- c++入门教程(六)
- 题目242-计算球体积
- 课时19 Linux多命令协作:管道及重定向
- Codeforces 739B【树上倍增+差分】
- iOS逆向之一--第一个tweak工程
- UI 一一 手把手教你封装一个广告轮播图框架
- 运行tensorflow程序是提示‘ImportError: No module named contrib.learn.python.learn.datasets’
- Git-记不住的命令整理
- CoreJava——基础语法
- JavaScript DOM编程艺术 读后感
- HIVE入门一之数据库DDL语句
- 【字典树】小练
- laravel 5.4框架路由get路由奇怪设定 有人能给我解释下为什么这样的么?
- PHP如何在MVC模型中使用回调函数