UIScrollView的滑动视图切换(懒加载)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UIScrollView的滑动视图切换(懒加载)相关的知识,希望对你有一定的参考价值。
最近在做一个股票项目,项目中有这么一个需求,利用UIScrollView左右切换去展示新闻资讯的详情,而且资新闻资讯很多。用zaker看过新闻的都应该很熟悉这个场景了。我的第一反应就是UIScrollView的懒加载。具体思路就是整个UIScrollView中只加载三个视图,这里用左、中、右来区分。下面说说我的具体实现,以期抛砖引玉。
在进入详情之前,是新闻的标题展示页,用UITableView展示的。点击某个标题,就进入到了该条新闻的详情页了。注意了,你需要把该新闻是第几条的索引值pageIndex传过去,以便在UIScrollView进行切换新闻详情的时候,对其进行标识。我是通过UIViewController的init方法传过去的
- (instancetype)initWithWithPageIndex:(NSInteger)pageIndex withDatas:(NSArray *)newsList
其中,newList里面有很多新闻的model,用于数据请求传参。
这时候新闻详情页里面初始化了三条新闻,它们分别是第(pageIndex-1)条,第pageIndex条,第(pageIndex+1)条。当拖动UIScrollView向右滚动到下一页时,将pageIndex加1。同时,将原来的三条最左边展示新闻内容的视图干掉,中间和右边的视图则保留,还有就是把新的第(pageIndex+1)加载出来。拖动UIScrollView向右滚动查看新闻时就是这样。那么向左查看上一页新闻详情呢?与向右查看类似,当翻到上一页时,将pageIndex减1,同时,将原来的三条最右边展示新闻内容的视图干掉,保留左边和中间的视图,把新的第(pageIndex-1)条新闻的详情加载出来。核心思想就是这些,先看看我写的demo代码吧(代码中将新闻展示换成了图片展示)
@interface CycleViewController () <UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
// 传过来的数据
@property (nonatomic, strong) NSArray *datas;
// 当前界面的索引 从0开始,最大值为传过来的资源数量减1
@property (nonatomic, assign) NSInteger pageIndex;
// 用于存放当前界面中的三个元素
@property (nonatomic, strong) NSMutableArray *tempDatas;
// 当前视图的最右边的偏移量,用以判断当前视图是否离开了屏幕(查看下一页时)
@property (nonatomic, assign) CGFloat leftOffsetX;
// 当前视图的最左边的偏移量,用以判断当前视图是否离开了屏幕(查看上一页时)
@property (nonatomic, assign) CGFloat rightOffsetX;
// startContentOffsetX和willEndContentOffsetX是用来判断向左还是向右的。这里,我将查看下一页定义为向右,反之向左
@property (nonatomic, assign) CGFloat startContentOffsetX;
@property (nonatomic, assign) CGFloat willEndContentOffsetX;
@property (nonatomic, assign) BOOL isDragged;
@end
#define kScrollViewWidth CGRectGetWidth(self.scrollView.frame)
#define kScrollViewHeight CGRectGetHeight(self.scrollView.frame)
@implementation CycleViewController
- (instancetype)initWithWithPageIndex:(NSInteger)pageIndex
withDatas:(NSArray *)datas {
self = [super init];
if (self) {
self.pageIndex = pageIndex;
self.datas = datas;
_isDragged = NO;
}
return self;
}
- (NSMutableArray *)tempDatas {
if (!_tempDatas) {
_tempDatas = [NSMutableArray arrayWithCapacity:3];
}
return _tempDatas;
}
- (void)loadView {
[super loadView];
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.delegate = self;
self.scrollView.directionalLockEnabled = YES;
self.scrollView.pagingEnabled = YES;
[self.view addSubview:self.scrollView];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
// 设置contentsize的height为0,意为scrollView的竖直方向不能拖动,解决scrollView的嵌套问题
self.scrollView.contentSize = CGSizeMake(kScrollViewWidth*self.datas.count, 0);
// 根据传过来的pageIndex进行初始化
[self configImages];
// 根据传过来的page索引值去初始化scrollView的偏移量
[self.scrollView setContentOffset:CGPointMake(kScrollViewWidth*self.pageIndex, 0)];
}
- (UIImageView *)configImageViewWithImage:(UIImage *)image withFrame:(CGRect)frame {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = image;
return imageView;
}
- (void)configImages {
UIImageView *firstImageView = nil;
UIImageView *secondImageView = nil;
UIImageView *thirdImageView = nil;
// 当图片的数量小于三个情况 UIScrollView把图片都加载出来展示
if (self.datas.count <= 3) {
firstImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas firstObject]] withFrame:CGRectMake(0, 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:firstImageView];
if (self.datas.count >= 2) {
secondImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:1]] withFrame:CGRectMake(kScrollViewWidth, 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:secondImageView];
if (self.datas.count >= 3) {
thirdImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:2]] withFrame:CGRectMake(kScrollViewWidth*2, 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:thirdImageView];
}
}
}
// 当图片数量大于三个的情况下 根据索引值 初始化三个视图,然后放在scrollView上面
else {
if (self.pageIndex < 2) { // 当索引值小于2的情况,初始化所有图片的前三个
secondImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:1]] withFrame:CGRectMake(kScrollViewWidth, 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:secondImageView];
firstImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas firstObject]] withFrame:CGRectMake(0, 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:firstImageView];
thirdImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:2]] withFrame:CGRectMake(kScrollViewWidth*2, 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:thirdImageView];
}
else if (self.pageIndex > self.datas.count-3) { // 初始化所有新源的最后三个
secondImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:self.datas.count-2]] withFrame:CGRectMake(kScrollViewWidth*(self.datas.count-2), 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:secondImageView];
firstImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:self.datas.count-3]] withFrame:CGRectMake(kScrollViewWidth*(self.datas.count-3), 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:firstImageView];
thirdImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:self.datas.count-1]] withFrame:CGRectMake(kScrollViewWidth*(self.datas.count-1), 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:thirdImageView];
}
else { // 初始化索引值及其所有的图片内容
secondImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:self.pageIndex]] withFrame:CGRectMake(kScrollViewWidth*self.pageIndex, 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:secondImageView];
firstImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:self.pageIndex-1]] withFrame:CGRectMake(kScrollViewWidth*(self.pageIndex-1), 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:firstImageView];
thirdImageView = [self configImageViewWithImage:[UIImage imageNamed:[self.datas objectAtIndex:self.pageIndex+1]] withFrame:CGRectMake(kScrollViewWidth*(self.pageIndex+1), 0, kScrollViewWidth, kScrollViewHeight)];
[self.scrollView addSubview:thirdImageView];
}
}
// 这里添加的顺序要注意,不是随便添加的
[self.tempDatas addObject:firstImageView];
if (secondImageView != nil) {
[self.tempDatas addObject:secondImageView];
}
if (thirdImageView != nil) {
[self.tempDatas addObject:thirdImageView];
}
self.leftOffsetX = kScrollViewWidth*(self.pageIndex+1);
self.rightOffsetX = kScrollViewWidth*self.pageIndex;
// 刚开始点击了第几张
self.title = [NSString stringWithFormat:@"第 %ld 张", self.pageIndex+1];
}
#pragma mark == UIScrollViewDelegate ==
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
self.isDragged = YES;
// 拖拽图片的起始偏移量
self.startContentOffsetX = scrollView.contentOffset.x;
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
// 将要停止拖拽时 scrollView偏移的位置
self.willEndContentOffsetX = scrollView.contentOffset.x;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (self.isDragged) {
BOOL directionRight;
CGFloat currentOffsetX = scrollView.contentOffset.x;
if (currentOffsetX > self.willEndContentOffsetX && self.willEndContentOffsetX > self.startContentOffsetX) {
directionRight = YES; // scrollView向右偏移
// 当前是第几张
int currentPage = ceil(scrollView.contentOffset.x/CGRectGetWidth(scrollView.frame))+1;
if (currentPage <= self.datas.count) {
self.title = [NSString stringWithFormat:@"第 %d 张", currentPage];
}
}
else if (currentOffsetX < self.willEndContentOffsetX && self.willEndContentOffsetX < self.startContentOffsetX) {
directionRight = NO; // scrollView向左偏移
// 当前是第几张
int currentPage = ceil(scrollView.contentOffset.x/CGRectGetWidth(scrollView.frame))+1;
if (currentPage > 0) {
self.title = [NSString stringWithFormat:@"第 %d 张", currentPage];
}
}
else {
return; // 需要严格的条件判断 当滑动的幅度较小时,则不进行股票的预加载
}
if (directionRight) {
if (self.leftOffsetX <= scrollView.contentOffset.x) { // 当前视图已经从界面中移除出去
self.pageIndex++;
if (self.pageIndex >= self.datas.count-1) {
self.pageIndex = self.datas.count-1;
self.leftOffsetX = CGRectGetWidth(scrollView.frame)*self.datas.count;
self.rightOffsetX = CGRectGetWidth(scrollView.frame)*(self.datas.count-1);
return;
}
self.leftOffsetX = CGRectGetWidth(scrollView.frame)*self.pageIndex;
self.rightOffsetX = CGRectGetWidth(scrollView.frame)*(self.pageIndex-1);
}
}
else {
if (self.rightOffsetX >= scrollView.contentOffset.x) { // 当前视图已经从界面中移除出去
self.pageIndex--;
if (self.pageIndex <= 0) {
self.pageIndex = 0;
self.leftOffsetX = CGRectGetWidth(scrollView.frame);
self.rightOffsetX = 0;
return;
}
self.leftOffsetX = CGRectGetWidth(scrollView.frame)*self.pageIndex;
self.rightOffsetX = CGRectGetWidth(scrollView.frame)*(self.pageIndex-1);
}
}
}
}
// 这个方法里面 才真正进行视图内容的加载
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
int currentPage = ceil(scrollView.contentOffset.x/CGRectGetWidth(scrollView.frame))+1;
self.title = [NSString stringWithFormat:@"第 %d 张", currentPage];
if (self.isDragged) {
// 此处为容错判断 若滑动过快 将会导致currentPage与self.pageIndex不一致 此时 将scrollView上原来的视图删除掉,然后再进行重新布局
if (self.datas.count > 3) {
NSInteger currentPage = ceil(scrollView.contentOffset.x/CGRectGetWidth(scrollView.frame));
if (currentPage != self.pageIndex) {
self.pageIndex = currentPage;
if (self.pageIndex >= self.datas.count-1) {
self.pageIndex = self.datas.count-1;
}
if (self.pageIndex <= 0) {
self.pageIndex = 0;
}
for (UIImageView *imageView in self.tempDatas) {
[imageView removeFromSuperview];
}
以上是关于UIScrollView的滑动视图切换(懒加载)的主要内容,如果未能解决你的问题,请参考以下文章 使用键盘时使用 UIScrollView 滑动并向上移动视图