实现自定义延迟加载的滚动视图

数据量大,单个数据处理耗时的情况下,一个延迟加载的自定义视图就必不可少了。我们希望这样的视图可以

在需要用到某个数据源的时候再去装载这个数据并处理之。而不是视图已启动就把全部的数据都加载上去。如果

全部加载再加上服务器请求(如果有的话)的时间绝对超过用户忍耐的极限。随之应用必然遭弃!

 

UITableView也有一定的复用机制。大概的机理是:每次到一个Cell出现在可视区域的时候,它会从已经用过的Cell中

取出来一个, 如果还没有用过的Cell(也就是说这个返回值是空)就创建一个。当一个Cell划出可视范围的时候就把这个

Cell放到备用数组中供以后使用。如下代码中就有所体现:

 1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
 2     static NSString *CellIdentifier = @"HomeCellIdentifier";
 3
 4     MyHomeCell *cell = (MyHomeCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 5     MyDataSource *content = (MyDataSource *)self.items[indexPath.row];
 6     if (!cell) {
 7         cell = [[[MyHomeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
 8     }
 9     [cell setContent:content];
10
11
12     return cell;
13 }

这里没有的就是回收不在显示范围的Cell的步骤,其代码应该是这样的:

 1 - (void)recycleView:(UITableViewCell *)cell
 2 {
 3     if (!cell)
 4     {
 5         return;
 6     }
 7
 8     [cell retain];
 9     [cell removeFromSuperview];              //从主界面中删除
10     [_visibleViews removeObject:cell];       //从可视的数组中删除
11     [_reuseableViews addObject:cell];        //放到回收数组中
12     [cell release];
13 }

dequeueReusableCellWithIdentifier这个方法都做了些神马呢,这里有一个模拟:

 1 - (UITableViewCell *)dequeueReusableView
 2 {
 3     UITableViewCell *reuseableCell = [_reuseableViews anyObject];
 4     if (reuseableCell)
 5     {
 6         [[reuseableCell retain] autorelease];
 7         [_reuseableViews removeObject:reuseableCell];
 8     }
 9     return reuseableCell;
10 }

从中可以看出。UITableView的复用机制包括两个数组:一个存放显示区域中的Cell,一个存放不在显示区域中的Cell。

当然UITableView实际的服用机制要比这个复杂。比如我们没有提到的CellIdentifier。这个与本文的中心有所偏离,各位可以自行研究。

 

UITableView虽然好用,但是不能满足所有的需求。所以很多人集成UIScrollView实现滚动视图。但是机制都和UITableView差不多。

实现出来的效果也是手指快速从屏幕上划过,一堆的Cell一样的视图轱辘个没完。

那么如何能够一次滑动只滚动一个“Cell”,或者说是翻一页。而且同时加载这一页对应的数据呢?

 

各位应该都看过杂技的一个最简单的节目,几个球在空中扔来扔去的。这个可以简单到只用两个视图交替展示一个旧的和一个新的视图,

从一个方向依次滚动,然后复位,装填一旧一新的数据,然后再滚动,再复位。在用户的眼前看到的可以是一个无穷循环播放的视图。

在这个视图初始化的时候:

 1 _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
 2         [self addGestureRecognizer:_panGesture];
 3         _panGesture.delegate = self;
 4         [_panGesture release];
 5
 6         _leftView = [[UIView alloc] initWithFrame:CGRectMake(0
 7                                                              , 0
 8                                                              , UISCREEN_MAINSCREEN_WIDTH
 9                                                              , UISCREEN_MAINSCREEN_HEIGHT)];
10         _leftView.backgroundColor = [UIColor whiteColor];
11         _rightView = [[UIView alloc] initWithFrame:CGRectMake(UISCREEN_MAINSCREEN_WIDTH
12                                                               , 0
13                                                               , UISCREEN_MAINSCREEN_WIDTH
14                                                               , UISCREEN_MAINSCREEN_HEIGHT)];
15         _rightView.backgroundColor = [UIColor whiteColor];
16
17         [self addSubview:_leftView];
18         [self addSubview:_rightView];

UIPanGestureRecognizer是必须的,没有这个的话无法扑捉用户的手势操作。整个视图的结构是一个视图在最下面扑捉用户手势并作为其他附属视图的container。

另外还有两个轮换的子视图响应用户操作。

当用户操作的时候如此处理:

 1 - (void)panAction:(id)sender{
 2     switch (_panGesture.state) {
 3         case UIGestureRecognizerStateBegan:
 4             _startPoint = self.center;
 5         case UIGestureRecognizerStateChanged:{
 6 //            CGPoint translatedPoint = [panGesture translationInView:self];
 7 //            _leftView.center = CGPointMake(_startPoint.x + translatedPoint.x,
 8 //                                                    _startPoint.y);
 9 //            _rightView.center = CGPointMake(_startPoint.x + translatedPoint.x,
10 //                                            _startPoint.y);
11             break;
12         }
13         case UIGestureRecognizerStateCancelled:
14         case UIGestureRecognizerStateEnded:{
15             CGPoint translation = [_panGesture translationInView:self];
16             if (abs(translation.x) < kPanGestureDistance) {
17                 return;
18             }
19
20             HBRRotationViewDirection moveDirection;
21
22             if (translation.x > _startPoint.x) {
23                 moveDirection = HBRRotationViewDirectionRight;
24                 _dataSourceIndex = 0;
25             }
26             else{
27                 moveDirection = HBRRotationViewDirectionLeft;
28 //                    if (_dataSourceIndex-- == 0) {
29                     _dataSourceIndex++;
30 //                    }
31             }
32
33             if (_isAnimationExecuting) {
34                 return;
35             }
36
37             _isAnimationExecuting = YES;
38
39             [UIView animateWithDuration:kRotationAnimationTimeInterval
40                              animations:^{
41                                  if (_dataSourceIndex == 0 && moveDirection == HBRRotationViewDirectionRight) {
42                                      return;
43                                  }
44
45                                  if (_dataSourceIndex + 1 == self.dataSourceCount
46                                      && moveDirection == HBRRotationViewDirectionLeft) {
47                                      return;
48                                  }
49
50                                  _leftView.frame = CGRectMake(-320.f, 0, 320, UISCREEN_MAINSCREEN_HEIGHT);
51                                  _rightView.frame = CGRectMake(0, 0, 320, UISCREEN_MAINSCREEN_HEIGHT);
52                              }
53                              completion:^(BOOL finished){
54                                  UIView *tempView = _leftView;
55                                  _leftView = _rightView;
56                                  _rightView = tempView;
57                                  _leftView.frame = CGRectMake(0, 0, UISCREEN_MAINSCREEN_WIDTH, UISCREEN_MAINSCREEN_HEIGHT);
58                                  _rightView.frame = CGRectMake(UISCREEN_MAINSCREEN_WIDTH, 0, UISCREEN_MAINSCREEN_WIDTH
59                                                                , UISCREEN_MAINSCREEN_HEIGHT);
60                                  [_rightView removeAllSubViews];
61                                  HBRMaskView *maskView = [[HBRMaskView alloc] initWithFrame:CGRectMake(0, 0
62                                                                                                        , UISCREEN_MAINSCREEN_WIDTH
63                                                                                                        , UISCREEN_MAINSCREEN_HEIGHT)];
64                                  [_rightView addSubview:maskView];
65                                  [maskView release];
66
67                                  if (self.RotationAnimationCompleteBlock) {
68                                      self.RotationAnimationCompleteBlock(_leftView, _rightView, moveDirection, _dataSourceIndex);
69                                  }
70
71                                  _isAnimationExecuting = NO;
72                              }];
73             break;
74         }
75
76         default:
77             break;
78     }
79 }

当用户手指在屏幕上作出pan手势,并且移动距离达到触发视图行为的时候动画移动左视图出可视区域,同时右视图随着左视图移入可视区域。

之后交换左右视图指针值,然后清空右视图的全部子视图。

滚动视图和其superview通过一个block交互。

1 @property(nonatomic, copy) void(^RotationAnimationCompleteBlock)(UIView*, UIView*, HBRRotationViewDirection, NSInteger);

这个block会把当前滚动视图的左视图、右视图、移动方向和当前需要用到的数据index一起发送给superview。superView可以根据这些

参数加载所需的视图并把处理之后的数据按照需要的方式展现在滚动视图中。

调用滚动视图的代码:

1 //初始化滚动视图
2 _rotationView.RotationAnimationCompleteBlock = ^(UIView *leftView, UIView *rightView
3                                                                      , HBRRotationViewDirection moveDirection
4                                                                      , NSInteger index){
5         [self rotationAction:leftView rightView:rightView direction:moveDirection index:index];
6     };

调用滚动视图代码:

 1 - (void)rotationAction:(UIView *)leftView rightView:(UIView *)rightView
 2              direction:(HBRRotationViewDirection)moveDirection index:(NSInteger)dataSourceIndex{
 3     DLog(@"Rotation Block");
 4     HBRWebView *webView;
 5     switch (moveDirection) {
 6         case HBRRotationViewDirectionStartPoint:{
 7             //开始运行
 8
 9             break;
10         }
11         case HBRRotationViewDirectionLeft:{
12             //手指左移
13             DLog(@"move left");
14             break;
15         }
16         case HBRRotationViewDirectionRight:{
17             DLog(@"move right");
18             [self.navigationController popViewControllerAnimated:YES];
19
20             break;
21         }
22         default:
23             break;
24     }
25 }

是指移动方向枚举:

typedef NS_ENUM(NSInteger, HBRRotationViewDirection) {
    HBRRotationViewDirectionLeft,
    HBRRotationViewDirectionRight,
    HBRRotationViewDirectionStartPoint,
};

枚举中第三项StartPoint是说在视图第一次在superView中加载上来的时候的状态。

同时开发这个滚动视图时还需要考虑的到如果到了数据源的最后一项如何处理。在这里用户手指向右滑动的时候跳转到上一层controller。

 

先写到这里了。谢谢 :)

 

 

 

 

 

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 330987132 | Go:217696290 | Python:336880185 | 做人要厚道,转载请注明出处!http://www.cnblogs.com/sunshine-anycall/p/3257399.html

时间: 2024-08-06 03:06:45

实现自定义延迟加载的滚动视图的相关文章

Android零基础入门第61节:滚动视图ScrollView

原文:Android零基础入门第61节:滚动视图ScrollView    前面几期学习了ProgressBar系列组件.ViewAnimator系列组件.Picker系列组件和时间日期系列组件,接下来几期继续来学习常见的其他组件.     一.ScrollView概述       从前面的学习有的同学可能已经发现,当拥有很多内容时屏幕显示不完,显示不全的部分完全看不见.但是在实际项目里面,很多内容都不止一个屏幕宽度或高度,那怎么办呢?那就需要本节学习的ScrollView来完成.     在默

Android开发入门(五)屏幕组件 5.7 ScrollView滚动视图

ScrollView是一种特殊的FrameLayout,使用ScrollView可以使用户能够滚动一个包含views的列表,这样 做的话,就可以利用比物理显示区域更大的空间.有一点需要注意一下,那就是ScrollView只能包含一个子 视图view或ViewGroup(这个ViewGroup通常是LinearLayout). 不要混合使用ListView和ScrollView .ListView被设计用来显示一些相关的信息,同时,ListView也已经被优化了去显示大量的列表lists. 下面的

vc++ 滚动视图-怎样在vc++多文档滚动视图中,用鼠标拖动滚动条,屏幕内容不变,自己处理显示内容

问题描述 怎样在vc++多文档滚动视图中,用鼠标拖动滚动条,屏幕内容不变,自己处理显示内容 我用vc++做了一个多文档程序,并用使用了滚动视图.现在,我想不使用系统提供的滚动功能,就是说,当我把滚动条拖动到某一位置后,屏幕显示内容不是有系统自动进行滚动,而是由我自己滚据滚动条的位置来处理显示内容,请问如何做?

滑动-有CCScrollView滚动视图中添加滚动条示例

问题描述 有CCScrollView滚动视图中添加滚动条示例 就像手机QQ或者微信聊天界面似的左边那条滚动条,当你滑动页面的时候滚动条就显示在当前文本的具体位置,不滑动的时候滚动条就消失,滚动条还随着文本内容的多少而发生长短变化 解决方案 class CCBarScrollView:public ScrollView { public: static CCBarScrollView* create(Size size, Node* container = NULL); static CCBarS

iOS 高性能异构滚动视图构建方案 —— LazyScrollView

##LazyScroll是什么 LazyScrollView 继承自ScrollView,目标是解决异构(与TableView的同构对比)滚动视图的复用回收问题.它可以支持跨View层的复用,用易用方式来生成一个高性能的滚动视图.此方案最先在天猫iOS客户端的首页落地. 为什么要用LazyScrollView 猫客首页之前首页的View比较少,不需要复用和回收也有很优秀的性能,但是之后首页的View数量逐渐膨胀,没有一套复用回收机制的ScrollView已经影响到性能了,迫切需要处理对Scrol

scrollview-如何给滚动视图设置成图像显示?

问题描述 如何给滚动视图设置成图像显示? 我使用水平滚动视图,并且在视图上动态的添加项目.如果项目的数量超过能在屏幕上能显示的数量,我想用如下图显示的,用箭头形式水平滚动来显示这些项目.怎么实现呢?这是我使用的XML代码: <HorizontalScrollView android:layout_width=""wrap_content"" android:scrollbars=""none"" android:id=&

禁止 gallery 在 android 上滚动视图

问题描述 禁止 gallery 在 android 上滚动视图 我使用 Gallery 来显示照片. 触屏时图像可以滚动到之前的图像和后面的图像. 我想设置一个按钮来锁定 gallery . 用的下面的代码来实现: gallery.setEnabled(false); 但还是能通过触屏来滚动视图,如何来锁定 gallery ? 解决方案 继承gallery重写里面的onFling方法 public boolean onFling(MotionEvent e1, MotionEvent e2, f

ios之UIScrollerView滚动视图

UIScrollView 类负责所有基于 UIKit 的滚动操作. 一.创建 [java] view plaincopy CGRect bounds = [ [ UIScreen mainScreen ] applicationFrame ] ;   UIScrollView* scrollView = [ [UIScrollView alloc ] initWithFrame:bounds ];   当你创建完滚动视图后,你可以将另一个视图的内容粘合到滚动视图的空白页上.这回创建一个滚动的内容

《iOS 6核心开发手册(第4版)》——1.13节秘诀:从滚动视图中拖动

1.13 秘诀:从滚动视图中拖动 iOS 6核心开发手册(第4版) iOS的丰富的姿势识别器集并不总是能够准确地实现你想要达到的目标.下面举一个例子.设想一个水平滚动的视图,其中一个接一个地填充图像视图,因此可以左右滚动,查看完整的集合.现在,设想你希望能够把项目拖出那个视图,并把它们添加到滚动区域下面的空间中.为此,需要识别那些子视图上向下的触摸(也就是说,垂直于滚动的方向). 这是我在尝试帮助开发人员Alex Hosgrove时所遇到的一道难题,他尝试构建一个应用程序,它粗略等价于一组冰箱磁