【问题标题】:UIScrollView. Any thoughts on implementing "infinite" scroll/zoom?UI滚动视图。关于实现“无限”滚动/缩放的任何想法?
【发布时间】:2010-12-02 09:52:33
【问题描述】:

所以,UITableView 基本上支持“无限”滚动。可能有一个限制,但那个傻瓜可以滚动很长时间。我想用 UIScrollView 来模仿这种行为,但有两个基本障碍:

1) scrollView.contentSize 在创建时是固定的。 2) 缩放可以将任何延迟加载方案彻底摧毁,因为它会导致无限数据爆炸。

有没有其他人思考过这个想法?是的,我知道,我们本质上是在讨论重新创建谷歌地图。任何见解将不胜感激。

干杯, 道格

【问题讨论】:

  • 好吧 UITableView 是 UIScrollView 的子类

标签: iphone cocoa-touch uiscrollview


【解决方案1】:

我刚刚为我完成了无限滚动。 在我的实现中,我有 UITableViewCell 和滚动视图和导航按钮。 scrollView 包含 x 个视图,所有视图都具有相同的宽度。视图水平排列并启用分页。

scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = NO;

我的代码逻辑如下:

  1. 在我的初始化函数中,我
    • 创建所有视图(用于滚动视图)和
    • 将它们放入一个数组中并
    • 将它们添加到滚动视图中
  2. 然后我调用一个函数,在循环中计算每个视图的位置(每次检测到滚动时,也需要调用这个函数)。它总是采用数组的第一个元素并将框架设置为 (0,0,...,...),第二个使用 (i*width,0,....,....) 等等在。被调用的函数如下所示:

    - (void)updateOffsetsOfViews{
        int xpos = 0;
        for (int i=0; i<[views count]; i++) {
            UIImageView *_view = [views objectAtIndex:i];
            CGRect aFrame = _view.frame;
            aFrame.origin.x = xpos;
            aFrame.origin.y = 0.0;
            _view.frame = aFrame;
            xpos += viewWidth;
        }
        float center = 0;
        if(fmod([views count],2) == 1){
            center = viewWidth * ([views count]-1)/2;
        }else {
            center = viewWidth * [views count]/2;
        }
        [scrollView setContentOffset:CGPointMake(center, 0)];
        lastOffset = center;
    }
    
  3. 然后(还在初始化过程中)我添加一个观察者

    [scrollView addObserver:self forKeyPath:@"contentOffset" options:0 context:nil];
    

    所以每次滚动视图中的某些内容发生变化时,我都会调用 (observeValueForKeyPath) 函数,如下所示:

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object  change:(NSDictionary *)change context:(void *)context
    {
        UIImageView *_viewFirst = (UIImageView *)[views objectAtIndex:0];
        if ( fmod([scrollView contentOffset].x,viewWidth)  == 0.0) {
            if ([scrollView contentOffset].x > lastOffset) {
                [views removeObjectAtIndex:0];
                [views addObject:_viewFirst];                
                [self updateOffsetsOfViews];    
            }else if ([scrollView contentOffset].x < lastOffset) {
                UIImageView *_viewLast = (UIImageView *)[views lastObject];
                [views removeLastObject];
                [views insertObject:_viewLast atIndex:0];            
                [self updateOffsetsOfViews];
            }
        }
    }
    
  4. 并且在 dealloc 或 viewDidUnload 中(取决于你如何实现它)不要忘记移除观察者。

    [scrollView removeObserver:self forKeyPath:@"contentOffset"];   
    

希望这会有所帮助,您可能会注意到一些开销,但在我的实现中,我还支持一次滚动 5 页(嗯...无限制)和自动动画滚动等,因此您可能会看到一些可能被丢弃的东西。

【讨论】:

  • 很好的解决方案,但是不要用==做浮点比较,会坏的。
  • 我试过你的代码。但是当我快速滚动 2 页时,代码将无法正确处理。
【解决方案2】:

虽然不可能拥有真正无限的 UIScrollView,但您可以使用一些简单的技巧来模拟这种行为。

  1. 处理固定的contentSize:让滚动视图处理一些固定大小的视图,并在启动或实例化时设置内容偏移量,以便您看到已处理视图的中间。然后只需观察内容偏移量(使用 KVO 或其他方法),如果您靠近任何边缘,使用一组新内容(适当偏移)更新视图的内容,并将滚动视图的 contentOffset 属性重置为返回在中间。
  2. 处理缩放:做类似的事情,只是这次注意滚动视图上的缩放系数。每当它到达某个点时,对您呈现的任何数据进行一些操作,使其显示为缩放,然后将缩放因子重置为 1.0。例如,如果您正在滚动图像并且它被缩放以显示两倍大,则以编程方式应用某种变换以使图像大两倍,然后将滚动视图的缩放因子重置为 1.0。图像仍会放大显示,但滚动视图将能够根据需要继续进一步放大。 (Google 地图更进一步,它会在用户缩放时延迟加载更详细的视图 - 您可以选择也可以不选择实现这一点。)

【讨论】:

  • 这个解决方案的问题是setContentOffset 取消正在发生的任何滚动并且运动突然停止。我不知道如何确定视图移动的速度,或者如果我这样做了如何重新启动该动作。
  • 但是为什么还要更改内容偏移量呢?让它滚动,只要确保你跟上并移动图像视图以对应用户所看到的。
  • 似乎setContentOffset:animated: 取消了当前滚动,但不是setContentOffset:... 在UIScrollView 的后代中覆盖setContentOffset: 并调整偏移有效! (至少在 iOS SDK 4.3 上)
【解决方案3】:

来自 Apple 的 StreetScroller 示例项目演示了如何在 UIScrollView 中执行无限滚动。

【讨论】:

    【解决方案4】:

    请记住,当滚动动画时,contentOffset 会多次更改,不仅是逐页更改,而是在动画中的每一步更改。

    【讨论】:

      【解决方案5】:

      也许将contentSize 设置为某个巨大的值,然后移动有限数量的底层视图以跟踪视图位置,如平铺示例中那样。

      为了减少最终到达边缘并不得不突然重新定位视图(这会取消当前运动中的任何滚动)的可能性,视图可以在静止时不时地重新定位。

      无论如何,这就是我要尝试的。

      【讨论】:

      • 这似乎工作正常,仅供参考。我正在使用 4 个包含的视图,其大小与随着滚动进行的包含视图的大小相同。我的代码基于滚动示例(上半部分)。
      • 苹果官方无限滚动示例项目建议使用此方法。
      猜你喜欢
      • 2014-12-06
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多