iOS-自动循环滚动视图

魏毅
2023-12-01
自动循环滚动视图
#import <UIKit/UIKit.h>

//1. 引入代理
@interface ReuseLoopView : UIView <UIScrollViewDelegate>

//2. 定义一个数组,dataArray中存放的是图片名
@property(nonatomic, strong) NSArray *dataArray;

//定时器
@property (nonatomic, strong) NSTimer *timer;

@end




#import "ReuseLoopView.h"

//定义屏幕的宽度
#define kScreenWidth [UIScreen mainScreen].bounds.size.width 
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

//定义分页控件的高度 
#define kPageControlHeight 37

@interface ReuseLoopView() {

//1. 定义三个视图:代表左边、中间和右边的视图,
//  思路:滑动时,就按照1、2、3、1、2、3、....
UIImageView *_leftImageView;
UIImageView *_centerImageView;
UIImageView *_rightImageView;

//2. 创建滑动视图和分页控件
UIScrollView *_scrollView;
UIPageControl *_pageControl;

//3. 存储当前页面的页码
NSInteger _currentPageNumber;
}

@end

@implementation ReuseLoopView

//1. 复写init方法 ----------> 保证每次创建的对象都是相同布局
- (instancetype) init {
//注意init这里的frame创建和initWithFrame创建布局不同
//解决:定义一个frame的全局变量即可
return [self initWithFrame:[UIScreen mainScreen].bounds];
}

//2. 复写initWithFrame方法
- (instancetype) initWithFrame:(CGRect)frame {

self = [super initWithFrame:frame];
if (self != nil) {
    //使用createUI来创建布局
    [self createUI:frame];
}

return self;
}

//3. 创建UI布局
- (void) createUI: (CGRect) frame {

//1) 创建滑动视图
//a) 初始化_scrollView
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, frame.size.height-kPageControlHeight)];
//b) 设置代理方法
_scrollView.delegate = self;
//c) 设置允许分页效果
_scrollView.pagingEnabled = YES;
//d) 隐藏水平垂直的滑动块
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
// e)设置是否有边界
_scrollView.bounces = NO;
//f) 添加到视图中
[self addSubview:_scrollView];

//2) 分页效果
//a) 初始化分页控件
_pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, frame.size.height - kPageControlHeight, kScreenWidth, kPageControlHeight)];
//b) 设置背景颜色
_pageControl.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"global_bg"]];

//c) 添加到视图中
[self addSubview:_pageControl];

//3) 初始化左、中、右的视图
//a) 初始化左边的视图
_leftImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.frame.size.width, _scrollView.frame.size.height)];
//b) 初始化中间的视图
_centerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(_scrollView.frame.size.width, 0, _scrollView.frame.size.width, _scrollView.frame.size.height)];
//c) 初始化右边的视图
_rightImageView = [[UIImageView alloc] initWithFrame:CGRectMake(_scrollView.frame.size.width*2, 0, _scrollView.frame.size.width, _scrollView.frame.size.height)];
//d) 将三张视图添加到滑动视图上
[_scrollView addSubview:_leftImageView];
[_scrollView addSubview:_centerImageView];
[_scrollView addSubview:_rightImageView];

//3)初始化timer,用这个方法初始化计时器不需要手动启动计时器,如果用init需要手动启动
_timer = [NSTimer scheduledTimerWithTimeInterval:1
                                      target:self
                                    selector:@selector(timeAction:)
                                    userInfo:nil
                                     repeats:YES];
}

#pragma mark - 定时器的实现方法
- (void) timeAction:(NSTimer *)timer {
//根据页码
NSInteger pageNum = _currentPageNumber % _dataArray.count;
_currentPageNumber = pageNum;
[self loadPageContent];
_currentPageNumber++;
}

//4. 设置初始化的数据
- (void) setInitProperty {

//1) 设置分页控件的页数
_pageControl.numberOfPages = _dataArray.count;
//2) 设置滑动区间
_scrollView.contentSize = CGSizeMake(_dataArray.count * _scrollView.frame.size.width, _scrollView.frame.size.height);
//3) 设置偏移量
_scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width, 0);
//4) 设置当前页数
_currentPageNumber = 0;
//5) 调用相关方法,加载图片
[self  loadPageContent];
}

//5. 加载页面内容
- (void) loadPageContent {

//1) 设置中间视图的图片:通过当前页码的指示器来获取图片
_centerImageView.image = [UIImage imageNamed:_dataArray[_currentPageNumber]];

//2) 设置左边的图片
//a) 获取指示器,注意_currentPageNumber = 0的情况
NSInteger leftImageIndex = (_currentPageNumber - 1 + _dataArray.count) % _dataArray.count;
//b) 设置图片
    _leftImageView.image = [UIImage imageNamed:_dataArray[leftImageIndex]];

//3) 设置右边的图片
    //b) 获取右边的指示器,注意_currentPageNumber = 4;
NSInteger rightImageIndex = (_currentPageNumber + 1) % _dataArray.count;
//c) 设置右边的图片
_rightImageView.image = [UIImage imageNamed:_dataArray[rightImageIndex]];

//4) 设置分页控件的当前页数
_pageControl.currentPage = _currentPageNumber;
}

//6. 复写_dataArray的set方法,目的是初始化
- (void) setDataArray:(NSArray *)dataArray {

//1) 注意一下,图片少于3张的情况,这个情况,大家自己考虑一下如何完成
//  解释:如果dataArray的类型不是数组,或者dataArray的数据少于3条,就返回
if ( ![dataArray isKindOfClass:[NSArray class]] || dataArray.count < 3 ) {
NSLog(@"图片数目不能少于3条...");
return;
}

//2) 传值
_dataArray = dataArray;

//3) 加载初始化数据
[self setInitProperty];

}

//7. 页面切换的代理方法处理
- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

//1) 打印滑动数据
NSLog(@"7.0 offset.x = %.2f, bounds.x = %.2f", _scrollView.contentOffset.x, _scrollView.bounds.size.width);

//2) 向左、向右滑动
/**
a) 当前的bounds.x(375) 是屏幕的宽度;
b) 但是在向左滑动的过程中,右边的imageView(+375)显示出来了,offset.x > bounds.x;
c) 向右滑动的时候,左边(负值-375)出来了,offset.x < bounds.x
 */
if (_scrollView.contentOffset.x > _scrollView.bounds.size.width) {

NSLog(@"7.1 向左边滑动...");
//说明:向左滑动,右边的图片出来,就+1
_currentPageNumber = (_currentPageNumber + 1) % _dataArray.count;

} else if(_scrollView.contentOffset.x < _scrollView.bounds.size.width) {    //向右滑动

NSLog(@"7.2 向右边滑动...");
//说明:向右滑动,左边的图片出来,就-1
_currentPageNumber = (_currentPageNumber - 1 + _dataArray.count) % _dataArray.count;

}

//2) 重新加载数据 -----> 如果不重新加载,那么每次就加载中间的图片
[self loadPageContent];

//3) 设置偏移量 -----> 因为加载的图片是中间的那张的那张图片,而中间的图片的偏移量正好是_scrollView.bounds.size.width
_scrollView.contentOffset = CGPointMake(_scrollView.bounds.size.width, 0);

}

// 滚动视图将要开始拖动滚动的时候的委托回调方法(自动调用偏移的时候不会回调这个方法,需外力作用,下面依旧是)
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self.timer invalidate];//取消计时器
self.timer = nil;//避免野指针
}

/**
*  滚动视图拖动滚动结束时候的委托回调方法(手拖动离开屏幕的时候)
* decelerate 是否减速
*/
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate     {
_timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
}


@end
 类似资料: