第一种
同学们在写需求的时候肯定会时常用到UIScrollView。而说到UIScrollView,大家最先想到的肯定就是它上面的无限轮播功能。苹果在UIScrollView上并没有提供相应的方法让大家实现轮播,所以就需要通过代码进行处理来实现。先上图
无限轮播效果图.gif
我先给大家讲讲其实现的原理:
我们假设用几张图片实现轮播效果。首先,我们需要打开UIScrollView的分页滑动
/// 分页滑动
_scrollView.scrollEnabled = YES;
它方便的帮助我们实现了轮播的效果,然后就需要我们来实现“无限的”轮播。接下来,我们就需要摆放图片了,在摆放图片时需要注意,我们需要在第一张图片的位置摆放最后一张图片(可能有点懵哈,不过不要着急慢慢往下看),然后我们依次摆放图片(从第一张到最后一张),最后在所有图片的尾部我们再放上第一张图片。这样我们就多放了两张图片(分别在首尾多放了一张图)。我把对应的方法写一下:
/// 将图片放置在UIScrollView上
-(void)setupImage {
/// 在UIScrollView的最前面添加一张图片
UIImageView *firstImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, self.scrollView.frame.size.height)];
/// 图片名是最后一张图片
firstImageView.image = [UIImage imageNamed:self.imageNameList.lastObject];
[self.scrollView addSubview:firstImageView];
/// 添加图片
for (NSInteger index = 0; index < self.imageNameList.count; index ++) {
/// UIScrollView上的每一张图片
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake((index + 1) * kScreenWidth, 0, kScreenWidth, self.scrollView.frame.size.height)];
imageView.image = [UIImage imageNamed:self.imageNameList[index]];
[self.scrollView addSubview:imageView];
self.scrollView.contentSize = CGSizeMake((index + 2) * self.scrollView.bounds.size.width, 0);
}
/// 在UIScrollView的最后面添加一张图片
UIImageView *lastImageView = [[UIImageView alloc] initWithFrame:CGRectMake((self.imageNameList.count + 1) * kScreenWidth, 0, kScreenWidth, self.scrollView.frame.size.height)];
/// 图片名是第一张图片
lastImageView.image = [UIImage imageNamed:self.imageNameList.firstObject];
[self.scrollView addSubview:lastImageView];
/// 设置UIScrollView的偏移量
self.scrollView.contentSize = CGSizeMake((self.imageNameList.count + 2) * self.scrollView.bounds.size.width, 0);
/// 设置UIScrollView的起始偏移距离(将第一张图片跳过)
self.scrollView.contentOffset = CGPointMake(kScreenWidth, 0);
/// 图片总数
self.pageControl.numberOfPages = self.imageNameList.count;
self.pageControl.currentPage = 0;
}
其实,如果大家看到这里,应该就会大致明白无线轮播的实现原理了。接下来就是最后一步,在UIScrollView的代理方法里面写逻辑:判断UIScrollView的偏移量,当其滑动到首位时(显示的是最后一张图片),滑动停止,就把偏移量修改最后面图片的位置上(倒数第二张)。同理,当UIScrollView滑动到最后时(显示的是第一张图片),滑动停止,就把偏移量修改到第一张图片的位置上(正数第二张)。
#pragma mark - UIScrollViewDelegate
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
/// 当UIScrollView滑动到第一位停止时,将UIScrollView的偏移位置改变
if (scrollView.contentOffset.x == 0) {
scrollView.contentOffset = CGPointMake(self.imageNameList.count * kScreenWidth, 0);
self.pageControl.currentPage = self.imageNameList.count;
/// 当UIScrollView滑动到最后一位停止时,将UIScrollView的偏移位置改变
} else if (scrollView.contentOffset.x == (self.imageNameList.count + 1)* kScreenWidth) {
scrollView.contentOffset = CGPointMake(kScreenWidth, 0);
self.pageControl.currentPage = 0;
} else {
self.pageControl.currentPage = scrollView.contentOffset.x / kScreenWidth - 1;
}
}
ok,原理其实就是这样。在首尾多加两张图片当做占位符,然后当UIScrollView滑动到占位符的位置时,改变UIScrollView的偏移量,简单且方便。下面就是全部代码:
#import "ViewController.h"
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
@interface ViewController () <UIScrollViewDelegate>
/// 滑动控制器
@property (nonatomic, strong) UIScrollView *scrollView;
/// 图片数组
@property (nonatomic, strong) NSArray<NSString *> *imageNameList;
/// 页码控制器
@property (nonatomic, strong) UIPageControl *pageControl;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置图片名的数组
self.imageNameList = @[@"image0", @"image1", @"image2", @"image3"];
// 添加图片
[self setupImage];
}
/// 将图片放置在UIScrollView上
-(void)setupImage {
/// 在UIScrollView的最前面添加一张图片
UIImageView *firstImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, self.scrollView.frame.size.height)];
/// 图片名是最后一张图片
firstImageView.image = [UIImage imageNamed:self.imageNameList.lastObject];
[self.scrollView addSubview:firstImageView];
/// 添加图片
for (NSInteger index = 0; index < self.imageNameList.count; index ++) {
/// UIScrollView上的每一张图片
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake((index + 1) * kScreenWidth, 0, kScreenWidth, self.scrollView.frame.size.height)];
imageView.image = [UIImage imageNamed:self.imageNameList[index]];
[self.scrollView addSubview:imageView];
self.scrollView.contentSize = CGSizeMake((index + 2) * self.scrollView.bounds.size.width, 0);
}
/// 在UIScrollView的最后面添加一张图片
UIImageView *lastImageView = [[UIImageView alloc] initWithFrame:CGRectMake((self.imageNameList.count + 1) * kScreenWidth, 0, kScreenWidth, self.scrollView.frame.size.height)];
/// 图片名是第一张图片
lastImageView.image = [UIImage imageNamed:self.imageNameList.firstObject];
[self.scrollView addSubview:lastImageView];
/// 设置UIScrollView的偏移量
self.scrollView.contentSize = CGSizeMake((self.imageNameList.count + 2) * self.scrollView.bounds.size.width, 0);
/// 设置UIScrollView的起始偏移距离(将第一张图片跳过)
self.scrollView.contentOffset = CGPointMake(kScreenWidth, 0);
/// 图片总数
self.pageControl.numberOfPages = self.imageNameList.count;
self.pageControl.currentPage = 0;
}
#pragma mark - UIScrollViewDelegate
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
/// 当UIScrollView滑动到第一位停止时,将UIScrollView的偏移位置改变
if (scrollView.contentOffset.x == 0) {
scrollView.contentOffset = CGPointMake(self.imageNameList.count * kScreenWidth, 0);
self.pageControl.currentPage = self.imageNameList.count;
/// 当UIScrollView滑动到最后一位停止时,将UIScrollView的偏移位置改变
} else if (scrollView.contentOffset.x == (self.imageNameList.count + 1)* kScreenWidth) {
scrollView.contentOffset = CGPointMake(kScreenWidth, 0);
self.pageControl.currentPage = 0;
} else {
self.pageControl.currentPage = scrollView.contentOffset.x / kScreenWidth - 1;
}
}
#pragma mark - Get方法
-(UIScrollView *)scrollView {
if (!_scrollView) {
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 200)];
_scrollView.pagingEnabled = YES;
_scrollView.clipsToBounds = NO;
_scrollView.scrollEnabled = YES;
_scrollView.delegate = self;
_scrollView.bounces = NO;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
[self.view addSubview:_scrollView];
}
return _scrollView;
}
-(UIPageControl *)pageControl {
if (!_pageControl) {
_pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 150, kScreenWidth, 50)];
_pageControl.pageIndicatorTintColor = [UIColor blackColor];
_pageControl.currentPageIndicatorTintColor = [UIColor grayColor];
[self.view addSubview:_pageControl];
}
return _pageControl;
}
@end
好了,如果大家使用的是swift语言,还可以参考这篇文章:https://www.jianshu.com/p/0ba33e59a784
作者:枫developer
链接:https://www.jianshu.com/p/7c4b79e5b123
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
第二种
#define SCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height // 主屏幕的高度
#define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width // 主屏幕的宽度
#define SCROLLVIEW_HEIGHT _testScrollview.bounds.size.height //testScrollview高度
#define SHOW_IMAGECOUNT 3
#import "ViewController.h"
@interface ViewController ()<UIScrollViewDelegate>
{
UIImageView *_leftImageView;
UIImageView *_centerImageView;
UIImageView *_rightImageView;
int _currentImageIndex;
}
@property (weak, nonatomic) IBOutlet UIScrollView *testScrollview;
@property (weak, nonatomic) IBOutlet UIPageControl *testPageCon;
@property (nonatomic, strong) NSMutableArray *imageData;
@end
@implementation ViewController
/**
*
* 加载数据
*
*/
-(NSMutableArray *)imageData{
if (!_imageData) {
_imageData = [NSMutableArray array];
for (int i = 1; i < 8; i++) {
[_imageData addObject:[UIImage imageNamed:[NSString stringWithFormat:@"%d.png",i]]];
}
}
return _imageData;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setScrollview];
[self setPageCon];
[self addImageViews];
[self loadDefaultImageView];
}
/**
*
* 设置scrollview
*
*/
-(void)setScrollview{
_testScrollview.contentSize = CGSizeMake(SCREEN_WIDTH * SHOW_IMAGECOUNT, SCROLLVIEW_HEIGHT);
_testScrollview.delegate = self;
[_testScrollview setContentOffset:CGPointMake(SCREEN_WIDTH, 0)];
_testScrollview.pagingEnabled = YES;
_testScrollview.showsHorizontalScrollIndicator=NO;
}
/**
*
* 设置分页控件
*
*/
-(void)setPageCon{
//注意此方法可以根据页数返回UIPageControl合适的大小
CGSize size= [_testPageCon sizeForNumberOfPages:self.imageData.count];
//设置颜色
_testPageCon.bounds=CGRectMake(0, 0, size.width, size.height);
_testPageCon.center = CGPointMake(SCREEN_WIDTH / 2, _testScrollview.frame.origin.y + SCROLLVIEW_HEIGHT - size.height);
_testPageCon.pageIndicatorTintColor=[UIColor colorWithRed:193/255.0 green:219/255.0 blue:249/255.0 alpha:1];
//设置当前页颜色
_testPageCon.currentPageIndicatorTintColor=[UIColor colorWithRed:0 green:150/255.0 blue:1 alpha:1];
//设置总页数
_testPageCon.numberOfPages = self.imageData.count;
}
/**
*
* 添加图片
*
*/
-(void)addImageViews{
_leftImageView=[[UIImageView alloc]initWithFrame:CGRectMake(0, _testScrollview.frame.origin.x, SCREEN_WIDTH, SCROLLVIEW_HEIGHT)];
_leftImageView.contentMode=UIViewContentModeScaleAspectFit;
[_testScrollview addSubview:_leftImageView];
_centerImageView=[[UIImageView alloc]initWithFrame:CGRectMake(SCREEN_WIDTH, _testScrollview.frame.origin.x, SCREEN_WIDTH, SCROLLVIEW_HEIGHT)];
_centerImageView.contentMode=UIViewContentModeScaleAspectFit;
[_testScrollview addSubview:_centerImageView];
_rightImageView=[[UIImageView alloc]initWithFrame:CGRectMake(2*SCREEN_WIDTH, _testScrollview.frame.origin.x, SCREEN_WIDTH, SCROLLVIEW_HEIGHT)];
_rightImageView.contentMode=UIViewContentModeScaleAspectFit;
[_testScrollview addSubview:_rightImageView];
}
/**
*
* 加载默认图片
*
*/
-(void)loadDefaultImageView{
_leftImageView.image = self.imageData.lastObject;
_centerImageView.image = self.imageData.firstObject;
_rightImageView.image = self.imageData[1];
_currentImageIndex = 0;
_testPageCon.currentPage = _currentImageIndex;
}
/**
*
* 更新图片
*
*/
-(void)updataImage{
int leftImageIndex,rightImageIndex;
CGPoint offset = [_testScrollview contentOffset];
if (offset.x > SCREEN_WIDTH) { //向右滑动
_currentImageIndex = (_currentImageIndex + 1) % self.imageData.count;
}else if(offset.x < SCREEN_WIDTH){ //向左滑动
_currentImageIndex = (int)(_currentImageIndex + self.imageData.count - 1) % self.imageData.count;
}
_centerImageView.image = self.imageData[_currentImageIndex];
//重新设置左右图片
leftImageIndex = (int)(_currentImageIndex + self.imageData.count - 1) % self.imageData.count;
rightImageIndex = (_currentImageIndex + 1) % self.imageData.count;
_leftImageView.image = self.imageData[leftImageIndex];
_rightImageView.image = self.imageData[rightImageIndex];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
//重新加载图片
[self updataImage];
//移动到中间
[_testScrollview setContentOffset:CGPointMake(SCREEN_WIDTH, 0)];
//设置分页
_testPageCon.currentPage=_currentImageIndex;
}
第三种
一、最终效果
二、原理说明
通过UICollectionView实现横向滚动轮播效果如下图所示,当移动到左右边缘后不可以继续移动
将CollectionView展开后的示意图如下:
思考:要使CollectionView滚动到左边缘和右边缘时均可以继续滚动,并且从左边缘向左滚动时显示的是最后一页,从右边缘向右滚动时显示的是第一页,可以在左边插入最后一页,在右边插入第一页,这样就可以滚动了。
示意图如下:
运行效果
现在还差最后一步了,当手动滚动到左侧第一页时,让CollectionView自动滚动到倒数第二页:
运行效果如下:
当手动滚动到最后一页时,让CollectionView自动滚动到正数第二页:
运行效果如下:
数据Setter方法如下:
-(void)setData:(NSArray<NSString *> *)data{
_titles = [NSMutableArray arrayWithArray:data];
//收尾分别插入一条数据
[_titles addObject:data.firstObject];
[_titles insertObject:data.lastObject atIndex:0];
//_collectionView滚动到第二页的位置
[_collectionView setContentOffset:CGPointMake(_collectionView.bounds.size.width, 0)];
//设置_pageControl的显示页数
_pageControl.numberOfPages = data.count;
}
通过代理方法更新CollectionView的滚动位置和PageControl的显示
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSInteger page = scrollView.contentOffset.x/scrollView.bounds.size.width;
NSLog(@"滚动到:%zd",page);
if (page == 0) {//滚动到左边
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width * (_titles.count - 2), 0);
_pageControl.currentPage = _titles.count - 2;
}else if (page == _titles.count - 1){//滚动到右边
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
_pageControl.currentPage = 0;
}else{
_pageControl.currentPage = page - 1;
}
}
最终得到如下效果:
Github
---------------------
作者:孟宪亮
来源:CSDN
原文:https://blog.csdn.net/u013282507/article/details/60583959
版权声明:本文为博主原创文章,转载请附上博文链接!
//
// NewPagedFlowView.m
// dianshang
//
// Created by sskh on 16/7/13.
// Copyright © 2016年 Mars. All rights reserved.
// Designed By PageGuo,
// QQ:799573715
// github:https://github.com/PageGuo/NewPagedFlowView
#import "HYNewPagedFlowView.h"
@interface HYNewPagedFlowView ()
@property (nonatomic, assign, readwrite) NSInteger currentPageIndex;
/**
* 计时器用到的页数
*/
@property (nonatomic, assign) NSInteger page;
/**
* 一页的尺寸
*/
@property (nonatomic,assign) CGSize pageSize;
@end
//子控制器的类名
static NSString *subviewClassName;
@implementation HYNewPagedFlowView
#pragma mark -
#pragma mark Private Methods
- (void)initialize{
self.clipsToBounds = YES;
self.needsReload = YES;
self.pageCount = 0;
self.isOpenAutoScroll = YES;
self.isCarousel = YES;
self.leftRightMargin = 20;
self.topBottomMargin = 30;
_currentPageIndex = 0;
_minimumPageAlpha = 1.0;
_autoTime = 5.0;
self.visibleRange = NSMakeRange(0, 0);
self.reusableCells = [[NSMutableArray alloc] initWithCapacity:0];
self.cells = [[NSMutableArray alloc] initWithCapacity:0];
self.scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
self.scrollView.scrollsToTop = NO;
self.scrollView.delegate = self;
self.scrollView.pagingEnabled = YES;
self.scrollView.clipsToBounds = NO;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
subviewClassName = @"PGIndexBannerSubiew";
[self addSubview:self.scrollView];
}
- (void)setLeftRightMargin:(CGFloat)leftRightMargin {
_leftRightMargin = leftRightMargin * 0.5;
}
- (void)setTopBottomMargin:(CGFloat)topBottomMargin {
_topBottomMargin = topBottomMargin * 0.5;
}
- (void)startTimer {
if (self.orginPageCount > 1 && self.isOpenAutoScroll && self.isCarousel) {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:self.autoTime target:self selector:@selector(autoNextPage) userInfo:nil repeats:YES];
self.timer = timer;
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
}
- (void)stopTimer {
if (self.timer) {
[self.timer invalidate];
self.timer = nil;
}
}
- (void)adjustCenterSubview {
if (self.isOpenAutoScroll && self.orginPageCount > 0) {
[_scrollView setContentOffset:CGPointMake(_pageSize.width * self.page, 0) animated:NO];
}
}
#pragma mark --自动轮播
- (void)autoNextPage {
self.page ++;
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:{
[_scrollView setContentOffset:CGPointMake(self.page * _pageSize.width, 0) animated:YES];
break;
}
case NewPagedFlowViewOrientationVertical:{
[_scrollView setContentOffset:CGPointMake(0, self.page * _pageSize.height) animated:YES];
break;
}
default:
break;
}
}
- (void)queueReusableCell:(PGIndexBannerSubiew *)cell{
[_reusableCells addObject:cell];
}
- (void)removeCellAtIndex:(NSInteger)index{
PGIndexBannerSubiew *cell = [_cells objectAtIndex:index];
if ((NSObject *)cell == [NSNull null]) {
return;
}
[self queueReusableCell:cell];
if (cell.superview) {
[cell removeFromSuperview];
}
[_cells replaceObjectAtIndex:index withObject:[NSNull null]];
}
- (void)refreshVisibleCellAppearance{
if (_minimumPageAlpha == 1.0 && self.leftRightMargin == 0 && self.topBottomMargin == 0) {
return;//无需更新
}
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:{
CGFloat offset = _scrollView.contentOffset.x;
for (NSInteger i = self.visibleRange.location; i < self.visibleRange.location + _visibleRange.length; i++) {
PGIndexBannerSubiew *cell = [_cells objectAtIndex:i];
subviewClassName = NSStringFromClass([cell class]);
CGFloat origin = cell.frame.origin.x;
CGFloat delta = fabs(origin - offset);
CGRect originCellFrame = CGRectMake(_pageSize.width * i, 0, _pageSize.width, _pageSize.height);//如果没有缩小效果的情况下的本该的Frame
if (delta < _pageSize.width) {
cell.coverView.alpha = (delta / _pageSize.width) * _minimumPageAlpha;
CGFloat leftRightInset = self.leftRightMargin * delta / _pageSize.width;
CGFloat topBottomInset = self.topBottomMargin * delta / _pageSize.width;
cell.layer.transform = CATransform3DMakeScale((_pageSize.width-leftRightInset*2)/_pageSize.width,(_pageSize.height-topBottomInset*2)/_pageSize.height, 1.0);
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(topBottomInset, leftRightInset, topBottomInset, leftRightInset));
} else {
cell.coverView.alpha = _minimumPageAlpha;
cell.layer.transform = CATransform3DMakeScale((_pageSize.width-self.leftRightMargin*2)/_pageSize.width,(_pageSize.height-self.topBottomMargin*2)/_pageSize.height, 1.0);
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(self.topBottomMargin, self.leftRightMargin, self.topBottomMargin, self.leftRightMargin));
}
}
break;
}
case NewPagedFlowViewOrientationVertical:{
CGFloat offset = _scrollView.contentOffset.y;
for (NSInteger i = self.visibleRange.location; i < self.visibleRange.location + _visibleRange.length; i++) {
PGIndexBannerSubiew *cell = [_cells objectAtIndex:i];
subviewClassName = NSStringFromClass([cell class]);
CGFloat origin = cell.frame.origin.y;
CGFloat delta = fabs(origin - offset);
CGRect originCellFrame = CGRectMake(0, _pageSize.height * i, _pageSize.width, _pageSize.height);//如果没有缩小效果的情况下的本该的Frame
if (delta < _pageSize.height) {
cell.coverView.alpha = (delta / _pageSize.height) * _minimumPageAlpha;
CGFloat leftRightInset = self.leftRightMargin * delta / _pageSize.height;
CGFloat topBottomInset = self.topBottomMargin * delta / _pageSize.height;
cell.layer.transform = CATransform3DMakeScale((_pageSize.width-leftRightInset*2)/_pageSize.width,(_pageSize.height-topBottomInset*2) / _pageSize.height, 1.0);
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(topBottomInset, leftRightInset, topBottomInset, leftRightInset));
cell.mainImageView.frame = cell.bounds;
} else {
cell.coverView.alpha = _minimumPageAlpha;
cell.frame = UIEdgeInsetsInsetRect(originCellFrame, UIEdgeInsetsMake(self.topBottomMargin, self.leftRightMargin, self.topBottomMargin, self.leftRightMargin));
cell.mainImageView.frame = cell.bounds;
}
}
}
default:
break;
}
}
- (void)setPageAtIndex:(NSInteger)pageIndex{
NSParameterAssert(pageIndex >= 0 && pageIndex < [_cells count]);
PGIndexBannerSubiew *cell = [_cells objectAtIndex:pageIndex];
if ((NSObject *)cell == [NSNull null]) {
cell = [_dataSource flowView:self cellForPageAtIndex:pageIndex % self.orginPageCount];
NSAssert(cell!=nil, @"datasource must not return nil");
[_cells replaceObjectAtIndex:pageIndex withObject:cell];
cell.tag = pageIndex % self.orginPageCount;
[cell setSubviewsWithSuperViewBounds:CGRectMake(0, 0, _pageSize.width, _pageSize.height)];
__weak __typeof(self) weakSelf = self;
cell.didSelectCellBlock = ^(NSInteger tag, PGIndexBannerSubiew *cell) {
[weakSelf singleCellTapAction:tag withCell:cell];
};
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:
cell.frame = CGRectMake(_pageSize.width * pageIndex, 0, _pageSize.width, _pageSize.height);
break;
case NewPagedFlowViewOrientationVertical:
cell.frame = CGRectMake(0, _pageSize.height * pageIndex, _pageSize.width, _pageSize.height);
break;
default:
break;
}
if (!cell.superview) {
[_scrollView addSubview:cell];
}
}
}
- (void)setPagesAtContentOffset:(CGPoint)offset{
//计算_visibleRange
CGPoint startPoint = CGPointMake(offset.x - _scrollView.frame.origin.x, offset.y - _scrollView.frame.origin.y);
CGPoint endPoint = CGPointMake(startPoint.x + self.bounds.size.width, startPoint.y + self.bounds.size.height);
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:{
NSInteger startIndex = 0;
for (int i =0; i < [_cells count]; i++) {
if (_pageSize.width * (i +1) > startPoint.x) {
startIndex = i;
break;
}
}
NSInteger endIndex = startIndex;
for (NSInteger i = startIndex; i < [_cells count]; i++) {
//如果都不超过则取最后一个
if ((_pageSize.width * (i + 1) < endPoint.x && _pageSize.width * (i + 2) >= endPoint.x) || i+ 2 == [_cells count]) {
endIndex = i + 1;//i+2 是以个数,所以其index需要减去1
break;
}
}
//可见页分别向前向后扩展一个,提高效率
startIndex = MAX(startIndex - 1, 0);
endIndex = MIN(endIndex + 1, [_cells count] - 1);
// self.visibleRange.location = startIndex;
// self.visibleRange.length = endIndex - startIndex + 1;
self.visibleRange = NSMakeRange(startIndex, endIndex - startIndex + 1);
for (NSInteger i = startIndex; i <= endIndex; i++) {
[self setPageAtIndex:i];
}
for (int i = 0; i < startIndex; i ++) {
[self removeCellAtIndex:i];
}
for (NSInteger i = endIndex + 1; i < [_cells count]; i ++) {
[self removeCellAtIndex:i];
}
break;
}
case NewPagedFlowViewOrientationVertical:{
NSInteger startIndex = 0;
for (int i =0; i < [_cells count]; i++) {
if (_pageSize.height * (i +1) > startPoint.y) {
startIndex = i;
break;
}
}
NSInteger endIndex = startIndex;
for (NSInteger i = startIndex; i < [_cells count]; i++) {
//如果都不超过则取最后一个
if ((_pageSize.height * (i + 1) < endPoint.y && _pageSize.height * (i + 2) >= endPoint.y) || i+ 2 == [_cells count]) {
endIndex = i + 1;//i+2 是以个数,所以其index需要减去1
break;
}
}
//可见页分别向前向后扩展一个,提高效率
startIndex = MAX(startIndex - 1, 0);
endIndex = MIN(endIndex + 1, [_cells count] - 1);
_visibleRange.location = startIndex;
_visibleRange.length = endIndex - startIndex + 1;
for (NSInteger i = startIndex; i <= endIndex; i++) {
[self setPageAtIndex:i];
}
for (NSInteger i = 0; i < startIndex; i ++) {
[self removeCellAtIndex:i];
}
for (NSInteger i = endIndex + 1; i < [_cells count]; i ++) {
[self removeCellAtIndex:i];
}
break;
}
default:
break;
}
}
#pragma mark -
#pragma mark Override Methods
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self initialize];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self initialize];
}
return self;
}
#pragma mark -
#pragma mark NewPagedFlowView API
- (void)reloadData {
_needsReload = YES;
//移除所有self.scrollView的子控件
for (UIView *view in self.scrollView.subviews) {
if ([NSStringFromClass(view.class) isEqualToString:subviewClassName] || [view isKindOfClass:[PGIndexBannerSubiew class]]) {
[view removeFromSuperview];
}
}
[self stopTimer];
if (_needsReload) {
//如果需要重新加载数据,则需要清空相关数据全部重新加载
//重置pageCount
if (_dataSource && [_dataSource respondsToSelector:@selector(numberOfPagesInFlowView:)]) {
//原始页数
self.orginPageCount = [_dataSource numberOfPagesInFlowView:self];
//总页数
if (self.isCarousel) {
_pageCount = self.orginPageCount == 1 ? 1: [_dataSource numberOfPagesInFlowView:self] * 3;
}else {
_pageCount = self.orginPageCount == 1 ? 1: [_dataSource numberOfPagesInFlowView:self];
}
//如果总页数为0,return
if (_pageCount == 0) {
return;
}
if (self.pageControl && [self.pageControl respondsToSelector:@selector(setNumberOfPages:)]) {
[self.pageControl setNumberOfPages:self.orginPageCount];
}
}
//重置pageWidth
_pageSize = CGSizeMake(self.bounds.size.width - 4 * self.leftRightMargin,(self.bounds.size.width - 4 * self.leftRightMargin) * 9 /16);
if (self.delegate && self.delegate && [self.delegate respondsToSelector:@selector(sizeForPageInFlowView:)]) {
_pageSize = [self.delegate sizeForPageInFlowView:self];
}
[_reusableCells removeAllObjects];
_visibleRange = NSMakeRange(0, 0);
//填充cells数组
[_cells removeAllObjects];
for (NSInteger index=0; index<_pageCount; index++)
{
[_cells addObject:[NSNull null]];
}
// 重置_scrollView的contentSize
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal://横向
_scrollView.frame = CGRectMake(0, 0, _pageSize.width, _pageSize.height);
_scrollView.contentSize = CGSizeMake(_pageSize.width * _pageCount,0);
CGPoint theCenter = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
_scrollView.center = theCenter;
if (self.orginPageCount > 1) {
if (self.isCarousel) {
//滚到第二组
[_scrollView setContentOffset:CGPointMake(_pageSize.width * self.orginPageCount, 0) animated:NO];
self.page = self.orginPageCount;
//启动自动轮播
[self startTimer];
}else {
//滚到开始
[_scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
self.page = self.orginPageCount;
}
}
break;
case NewPagedFlowViewOrientationVertical:{
_scrollView.frame = CGRectMake(0, 0, _pageSize.width, _pageSize.height);
_scrollView.contentSize = CGSizeMake(0 ,_pageSize.height * _pageCount);
CGPoint theCenter = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
_scrollView.center = theCenter;
if (self.orginPageCount > 1) {
if (self.isCarousel) {
//滚到第二组
[_scrollView setContentOffset:CGPointMake(0, _pageSize.height * self.orginPageCount) animated:NO];
self.page = self.orginPageCount;
//启动自动轮播
[self startTimer];
}else {
//滚到第二组
[_scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
self.page = self.orginPageCount;
}
}
break;
}
default:
break;
}
_needsReload = NO;
}
[self setPagesAtContentOffset:_scrollView.contentOffset];//根据当前scrollView的offset设置cell
[self refreshVisibleCellAppearance];//更新各个可见Cell的显示外貌
}
- (PGIndexBannerSubiew *)dequeueReusableCell{
PGIndexBannerSubiew *cell = [_reusableCells lastObject];
if (cell)
{
[_reusableCells removeLastObject];
}
return cell;
}
- (void)scrollToPage:(NSUInteger)pageNumber {
if (pageNumber < _pageCount) {
//首先停止定时器
[self stopTimer];
if (self.isCarousel) {
self.page = pageNumber + self.orginPageCount;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startTimer) object:nil];
[self performSelector:@selector(startTimer) withObject:nil afterDelay:0.5];
}else {
self.page = pageNumber;
}
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:
[_scrollView setContentOffset:CGPointMake(_pageSize.width * self.page, 0) animated:YES];
break;
case NewPagedFlowViewOrientationVertical:
[_scrollView setContentOffset:CGPointMake(0, _pageSize.height * self.page) animated:YES];
break;
}
[self setPagesAtContentOffset:_scrollView.contentOffset];
[self refreshVisibleCellAppearance];
}
}
#pragma mark -
#pragma mark hitTest
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self pointInside:point withEvent:event]) {
CGPoint newPoint = CGPointZero;
newPoint.x = point.x - _scrollView.frame.origin.x + _scrollView.contentOffset.x;
newPoint.y = point.y - _scrollView.frame.origin.y + _scrollView.contentOffset.y;
if ([_scrollView pointInside:newPoint withEvent:event]) {
return [_scrollView hitTest:newPoint withEvent:event];
}
return _scrollView;
}
return nil;
}
#pragma mark -
#pragma mark UIScrollView Delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (self.orginPageCount == 0) {
return;
}
NSInteger pageIndex;
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:
pageIndex = (int)round(_scrollView.contentOffset.x / _pageSize.width) % self.orginPageCount;
break;
case NewPagedFlowViewOrientationVertical:
pageIndex = (int)round(_scrollView.contentOffset.y / _pageSize.height) % self.orginPageCount;
break;
default:
break;
}
if (self.isCarousel) {
if (self.orginPageCount > 1) {
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:
{
if (scrollView.contentOffset.x / _pageSize.width >= 2 * self.orginPageCount) {
[scrollView setContentOffset:CGPointMake(_pageSize.width * self.orginPageCount, 0) animated:NO];
self.page = self.orginPageCount;
}
if (scrollView.contentOffset.x / _pageSize.width <= self.orginPageCount - 1) {
[scrollView setContentOffset:CGPointMake((2 * self.orginPageCount - 1) * _pageSize.width, 0) animated:NO];
self.page = 2 * self.orginPageCount;
}
}
break;
case NewPagedFlowViewOrientationVertical:
{
if (scrollView.contentOffset.y / _pageSize.height >= 2 * self.orginPageCount) {
[scrollView setContentOffset:CGPointMake(0, _pageSize.height * self.orginPageCount) animated:NO];
self.page = self.orginPageCount;
}
if (scrollView.contentOffset.y / _pageSize.height <= self.orginPageCount - 1) {
[scrollView setContentOffset:CGPointMake(0, (2 * self.orginPageCount - 1) * _pageSize.height) animated:NO];
self.page = 2 * self.orginPageCount;
}
}
break;
default:
break;
}
}else {
pageIndex = 0;
}
}
[self setPagesAtContentOffset:scrollView.contentOffset];
[self refreshVisibleCellAppearance];
if (self.pageControl && [self.pageControl respondsToSelector:@selector(setCurrentPage:)]) {
[self.pageControl setCurrentPage:pageIndex];
}
if (_delegate && [_delegate respondsToSelector:@selector(didScrollToPage:inFlowView:)] && _currentPageIndex != pageIndex && pageIndex >= 0) {
[_delegate didScrollToPage:pageIndex inFlowView:self];
}
_currentPageIndex = pageIndex;
}
#pragma mark --将要开始拖拽
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self stopTimer];
}
#pragma mark --结束拖拽
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
[self startTimer];
}
#pragma mark --将要结束拖拽
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
if (self.orginPageCount > 1 && self.isOpenAutoScroll && self.isCarousel) {
switch (self.orientation) {
case NewPagedFlowViewOrientationHorizontal:
{
if (self.page == floor(_scrollView.contentOffset.x / _pageSize.width)) {
self.page = floor(_scrollView.contentOffset.x / _pageSize.width) + 1;
}else {
self.page = floor(_scrollView.contentOffset.x / _pageSize.width);
}
}
break;
case NewPagedFlowViewOrientationVertical:
{
if (self.page == floor(_scrollView.contentOffset.y / _pageSize.height)) {
self.page = floor(_scrollView.contentOffset.y / _pageSize.height) + 1;
}else {
self.page = floor(_scrollView.contentOffset.y / _pageSize.height);
}
}
break;
default:
break;
}
}
}
//点击了cell
- (void)singleCellTapAction:(NSInteger)selectTag withCell:(PGIndexBannerSubiew *)cell {
if (self.delegate && [self.delegate respondsToSelector:@selector(didSelectCell:withSubViewIndex:)]) {
[self.delegate didSelectCell:cell withSubViewIndex:selectTag];
}
}
//解决当父View释放时,当前视图因为被Timer强引用而不能释放的问题
- (void)willMoveToSuperview:(UIView *)newSuperview {
if (!newSuperview) {
[self stopTimer];
}
}
//解决当timer释放后 回调scrollViewDidScroll时访问野指针导致崩溃
- (void)dealloc {
_scrollView.delegate = nil;
}
@end