UIKit之图片轮播器Demo

需求

实现图片轮播器,搭配页面指示器、可以自动轮播。
注意计时器优先级问题

分析

  1. 需要UIScrollView组件、指示器UIPageControl。此外自定义类需要实现代理
  2. 自动滚动需要监控当前屏幕的offsetx。
  3. 防止拖拽自动滚动时一下子翻滚太多的BUG:拖拽时,撤销当前timer,放开再创建新的timer。
  4. 注意计时器优先级问题,使用计时器,经常会出现被其它组件抢占线程的情况,所以代码要做出修改,修改消息循环中计时器的优先级。

实现

· 自定义类的创建:

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

问题

  1. UIImageView设置了图片不显示问题:
    UIScrollView没有初始化。
    图片像素太大,截小一点就出来了。