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];

    

    // 设置contentsizeheight0,意为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) {

        

        // 此处为容错判断 若滑动过快 将会导致currentPageself.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的滑动视图切换(懒加载)的主要内容,如果未能解决你的问题,请参考以下文章

TableView 加载图片优化(滑动不加载图片思路)

ViewPager+Fragment 懒加载

使用键盘时使用 UIScrollView 滑动并向上移动视图

UIScrollview 中的 UISwitch 几乎无法使用

UIScrollView 仅检测底部的滑动

UIScrollView,滑动,缩放