需求
实现图片轮播器,搭配页面指示器、可以自动轮播。
注意计时器优先级问题
分析
- 需要UIScrollView组件、指示器UIPageControl。此外自定义类需要实现代理
- 自动滚动需要监控当前屏幕的offsetx。
- 防止拖拽自动滚动时一下子翻滚太多的BUG:拖拽时,撤销当前timer,放开再创建新的timer。
- 注意计时器优先级问题,使用计时器,经常会出现被其它组件抢占线程的情况,所以代码要做出修改,修改消息循环中计时器的优先级。
实现
· 自定义类的创建:
objectivec
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface PicAutoPlayView : UIView<UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIPageControl *pagecontrol;
// 为图片滚动拖住不放而自动滚动的记时也停止,需要在类中引用计时器:否则有BUG
// 弱引用即可,销毁不跟随此类:在开始拖拽的方法中实现
@property(weak, nonatomic) NSTimer *timer;
@end
NS_ASSUME_NONNULL_END
· 功能实现:
objectivec
#import "PicAutoPlayView.h"
@implementation PicAutoPlayView
/*
遇到问题:
图片不显示:UIScrollView没有初始化
图片像素太大,截一下
此外,其它可滚动的同优先级组件在响应其它处理时,会影响当前自动滚动组件的计时器,因为主线程跑去执行那个任务了
消息循环:
// 获取当前消息循环对象
NSRunLoop:让timer优先级和当前控件一样,即可。
*/
/*
没有显示图片:
输出一下sc坐标和imgview坐标
*/
-(instancetype) initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
// 其实scrollview整个就是加进的全部UIImageView
_scrollView.backgroundColor = [UIColor grayColor];
// scrollview没有初始化,半天找不到它
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(10, 0, self.frame.size.width-10, 220)];
if(self){
// 需要靠左10和靠右10,注意我这里的写法,怎么空开的,和下面的x坐标如何对应起来的
CGFloat imgW = self.frame.size.width-20;
CGFloat imgH = 200;
for(int i = 0; i < 5 ; i++){
UIImageView *imgview = [[UIImageView alloc]init];
// 每个img的坐标
CGFloat imgx = imgW*i+10*i;
CGFloat imgy = 70;
imgview.frame = CGRectMake(imgx, imgy, imgW, imgH);
imgview.image = [UIImage imageNamed:[NSString stringWithFormat:@"img_%02d.png", i+1]];
// finditem_ad.png
[_scrollView addSubview:imgview];
}
// 设置滚动范围: 第二个位置传0表示:垂直方向不滚动
CGFloat scrollW = _scrollView.frame.size.width*5;
_scrollView.contentSize = CGSizeMake(scrollW, 0);
// 实现分页效果:(很简单):分页按照UIScrollView的宽度来分,所以内部图片大小和UIScrollView宽度一致即可
_scrollView.pagingEnabled = YES;
// 隐藏横轴:
_scrollView.showsHorizontalScrollIndicator = NO;
#pragma --mark 分页指示器设置
// pagecontrol属于UIView,不属于scrollview,因为页面滚动时,指示器得浮在表层。它俩没有关系
_pagecontrol = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 185, self.bounds.size.width, 30)];
_pagecontrol.numberOfPages = 5; // 设置总页数
_pagecontrol.currentPage = 0; // 设置当前显示的页数(默认为0)
_pagecontrol.pageIndicatorTintColor = [UIColor grayColor]; // 设置非当前页小圆点的颜色
_pagecontrol.currentPageIndicatorTintColor = [UIColor blueColor]; // 设置当前页小圆点的颜色
// 设置滚动时指示器点位置的变化:需要检测滚动位置事件
_scrollView.delegate = self; // 代理
#pragma --mark 计时器实现自动滚动
// 自动滚动:常用NSTimer方式:TimerWith、scheduleXXX,第一种需要手动添加到消息循环中,第二种是自动创建的
// 每隔多久时间执行哪个方法: 时间间隔、执行哪个对象的哪个方法
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(scrollImage) userInfo:nil repeats:YES];
self.timer = timer;
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
// timer对象的优先级
[runloop addTimer:self.timer forMode:NSRunLoopCommonModes];
}
[self addSubview:_scrollView];
[self addSubview:_pagecontrol];
return self;
}
/*
防止拖拽不动放开后 导致快速滑动的BUG:
在拖拽开始和结束时,停止计时器、重开启计时器
*/
-(void) scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
[self.timer invalidate];
}
//
-(void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
// 重新开一个计时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(scrollImage) userInfo:nil repeats:YES];
// 再改变优先级:
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
// timer对象的优先级
[runloop addTimer:self.timer forMode:NSRunLoopCommonModes];
}
// 实现拖动滚动:做滚动位置监控
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// CGPoint offset = scrollView.contentOffset;
// contentOffset包含了x、y,这里取x即可
CGFloat offset = scrollView.contentOffset.x;
int page = offset / scrollView.frame.size.width;
_pagecontrol.currentPage = page;
}
/*
自动滚动图片的方法:设置偏移值即可实现滚动
通过变量页码来设置当前的偏移量
如果页码到了最后一页,则设置页码为0,回第一页
*/
- (void)scrollImage{
// NSInteger:适合跨平台
NSInteger page = _pagecontrol.currentPage;
// 尾页则回到第一页
if(page == _pagecontrol.numberOfPages -1){
page = 0;
}else{
page++;
}
// 偏移量设置
CGFloat offsetx = page * _scrollView.frame.size.width;
[_scrollView setContentOffset:CGPointMake(offsetx, 0) animated:YES];
}
//
@end
问题
- UIImageView设置了图片不显示问题:
UIScrollView没有初始化。
图片像素太大,截小一点就出来了。