【问题标题】:How to know when UITableView did scroll to bottom in iPhone?如何知道 UITableView 何时在 iPhone 中滚动到底部?
【发布时间】:2011-07-05 12:11:57
【问题描述】:

我想知道UITableView 何时滚动到底部以加载和显示更多内容,例如委托或其他让控制器知道表格何时滚动到底部的东西。

我该怎么做?

【问题讨论】:

    标签: ios uitableview scroll


    【解决方案1】:

    在 tableview 委托中做这样的事情

    ObjC:

    - (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
        CGPoint offset = aScrollView.contentOffset;
        CGRect bounds = aScrollView.bounds;
        CGSize size = aScrollView.contentSize;
        UIEdgeInsets inset = aScrollView.contentInset;
        float y = offset.y + bounds.size.height - inset.bottom;
        float h = size.height;
        // NSLog(@"offset: %f", offset.y);   
        // NSLog(@"content.height: %f", size.height);   
        // NSLog(@"bounds.height: %f", bounds.size.height);   
        // NSLog(@"inset.top: %f", inset.top);   
        // NSLog(@"inset.bottom: %f", inset.bottom);   
        // NSLog(@"pos: %f of %f", y, h);
    
        float reload_distance = 10;
        if(y > h + reload_distance) {
            NSLog(@"load more rows");
        }
    }
    

    斯威夫特:

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offset = scrollView.contentOffset
        let bounds = scrollView.bounds
        let size = scrollView.contentSize
        let inset = scrollView.contentInset
        let y = offset.y + bounds.size.height - inset.bottom
        let h = size.height
        let reload_distance:CGFloat = 10.0
        if y > (h + reload_distance) {
            print("load more rows")
        }
    }
    

    【讨论】:

    • 好!只需使用:y >= h + reload_distance,这实际上只有当 reload_distance = 0 时才需要考虑(例如,对于反弹 NO)。
    • 当用户在屏幕上上下移动手指时,“scrollViewDidScroll”中的这段代码一直在执行。最好将其移动到“scrollViewDidEndDecelerating”下。这样,当用户停止移动手指时,它将执行一次。
    • 嗯..这段代码还能用吗?没有为我了解 UITableView 的底部。我希望我知道上面所有代码背后的原因,所以也许我可以修复
    • offset: 237.000000 content.height: 855.000000 bounds.height: 667.000000 inset.top: 64.000000 inset.bottom: 49.000000 pos: 855.000000 of 855.000000 如果是假的
    【解决方案2】:

    修改过的新手回答了一下。

    此答案针对那些只希望每次松开手指触发一次事件的人。

    适用于从某些内容提供商(网络服务、核心数据等)加载更多内容时。 请注意,此方法不考虑您的 Web 服务的响应时间。

    - (void)scrollViewDidEndDragging:(UIScrollView *)aScrollView
                      willDecelerate:(BOOL)decelerate
    {
        CGPoint offset = aScrollView.contentOffset;
        CGRect bounds = aScrollView.bounds;
        CGSize size = aScrollView.contentSize;
        UIEdgeInsets inset = aScrollView.contentInset;
        float y = offset.y + bounds.size.height - inset.bottom;
        float h = size.height;
    
        float reload_distance = 50;
        if(y > h + reload_distance) {
            NSLog(@"load more rows");
        }
    }
    

    【讨论】:

    • 这不起作用。每当用户滚动到底部时,都会调用“加载更多行”。即使用户已经滚动到底部并正在等待 API 返回数据,也会发生这种情况。
    • Dean,问题是要知道表格视图何时滚动到底部。您是否从 API 获取数据无关紧要,不是吗?
    • 但是没有消息显示加载更多.. 以便用户可以知道还有更多结果要显示。
    • 在我的情况下很好的答案,如果:float reload_distance = 10; if(y > (h - reload_distance)) { NSLog(@"加载更多行"); } 因为 y = 565 而 h 也是 565
    • 我尝试了 Eyeball 和 @neoneye 的答案。信不信由你,与“scrollViewDidEndDragging”相比,“scrollViewDidScroll”被调用了多次。所以使用'scrollViewDidEndDragging'是有效的,因为我有API调用。
    【解决方案3】:

    UITableViewDelegate中添加这个方法:

    -(void)scrollViewDidScroll:(UIScrollView *)scrollView
    {   
        CGFloat height = scrollView.frame.size.height;
    
        CGFloat contentYoffset = scrollView.contentOffset.y;
    
        CGFloat distanceFromBottom = scrollView.contentSize.height - contentYoffset;
    
        if(distanceFromBottom < height) 
        {
            NSLog(@"end of the table");
        }
    }
    

    【讨论】:

    • 我喜欢这个解决方案,除了一个小细节。 if(distanceFromBottom
    • 这帮助我解决了我的问题,谢谢!一个标签栏!!这是一个愚蠢的标签栏!
    • 这项工作就像一个魅力,它也很简单,但我面临一个小问题,比如它在最后一行执行了两三次。如何让它到达 tableview 的最后一行时只执行一次?
    • 非常感谢!!我把这段代码放在 scrollViewWillBeginDecelerating 中,当滚动到最后一行时它只执行一次。
    【解决方案4】:

    上面的答案都没有帮助我,所以我想出了这个:

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView
    {   
        NSArray *visibleRows = [self.tableView visibleCells];
        UITableViewCell *lastVisibleCell = [visibleRows lastObject];
        NSIndexPath *path = [self.tableView indexPathForCell:lastVisibleCell];
        if(path.section == lastSection && path.row == lastRow)
        {
            // Do something here
        }
    }
    

    【讨论】:

    • 你能详细说明“lastSection”的来源吗?
    • 这是滚动视图而不是表格
    【解决方案5】:

    最好的方法是在屏幕底部测试一个点,并在用户滚动时使用此方法调用 (scrollViewDidScroll):

    - (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point
    

    测试屏幕底部附近的一个点,然后使用它返回的 indexPath 检查该 indexPath 是否是最后一行,如果是,则添加行。

    【讨论】:

    • 很遗憾,我的App会实时更新这个表中已有行的数据,所以这种方式在表格完全不滚动的情况下可能会得到更多的内容。
    【解决方案6】:

    使用– tableView:willDisplayCell:forRowAtIndexPath:UITableViewDelegate方法)

    只需将indexPath 与数据数组(或用于表格视图的任何数据源)中的项目进行比较,即可确定是否显示最后一个元素。

    文档:http://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:willDisplayCell:forRowAtIndexPath

    【讨论】:

    • 那么,如果重新加载tableView的数据,就会陷入死循环。
    【解决方案7】:

    UITableViewUIScrollView 的子类,UITableViewDelegate 符合UIScrollViewDelegate。所以你附加到table view的delegate会得到scrollViewDidScroll:等事件,你可以在table view上调用contentOffset等方法来查找滚动位置。

    【讨论】:

    • 是的,这就是我要找的,通过实现该委托并检查滚动位置是否为 UITableViewScrollPositionBottom,我会知道表格何时滚动到底部,非常感谢
    【解决方案8】:
    NSLog(@"%f / %f",tableView.contentOffset.y, tableView.contentSize.height - tableView.frame.size.height);
    
    if (tableView.contentOffset.y == tableView.contentSize.height - tableView.frame.size.height)
            [self doSomething];
    

    漂亮又简单

    【讨论】:

      【解决方案9】:

      Swift 你可以做这样的事情。每次到达 tableview 的末尾时,以下条件都会为真

      func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
              if indexPath.row+1 == postArray.count {
                  println("came to last row")
              }
      }
      

      【讨论】:

      • 问题是当tableview只有3个单元格时,例如println("came to last row")这个代码运行!
      • @Mc.Lover 这对我来说正是 CPU 使用率达到 92% 的问题。 neoneye 的回答对我有用。如果您需要,我还为它添加了 swift 版本。
      【解决方案10】:

      以@Jay Mayu 的回答为基础,我认为这是更好的解决方案之一:

      Objective-C

      // UITableViewDelegate
      - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
      
      // Need to call the service & update the array
      if(indexPath.row + 1 == self.sourceArray.count) {
          DLog(@"Displayed the last row!");
        }
      }
      

      Swift 2.x

      // UITableViewDelegate
      func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
          if (indexPath.row + 1) == sourceArray.count {
              print("Displayed the last row!")
          }
      }
      

      【讨论】:

        【解决方案11】:

        这里是swift 3.0版本代码。

           func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
                let offset = scrollView.contentOffset
                let bounds = scrollView.bounds
                let size = scrollView.contentSize
                let inset = scrollView.contentInset
                let y: Float = Float(offset.y) + Float(bounds.size.height) + Float(inset.bottom)
                let height: Float = Float(size.height)
                let distance: Float = 10
        
                if y > height + distance {
                    // load more data
                }
            }
        

        【讨论】:

          【解决方案12】:

          我一般用这个来加载更多数据,当最后一个单元格开始显示时

          -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
          {
             if (indexPath.row ==  myDataArray.count-1) {
                  NSLog(@"load more");
              }
          }
          

          【讨论】:

          • 这是错误的。每次调用 reloadData 时都会发出一个请求。有时您只需要重新加载表格。
          • 您想说,如果您在最后一个单元格中然后重新加载数据,那么这会发生吗?
          【解决方案13】:

          采用neoneye 出色的答案,但要迅速,并重命名变量..

          如果yOffsetAtBottom 超出表格内容高度,基本上我们知道我们已经到达表格视图的底部。

          func isTableViewScrolledToBottom() -> Bool {
              let tableHeight = tableView.bounds.size.height
              let contentHeight = tableView.contentSize.height
              let insetHeight = tableView.contentInset.bottom
          
              let yOffset = tableView.contentOffset.y
              let yOffsetAtBottom = yOffset + tableHeight - insetHeight
          
              return yOffsetAtBottom > contentHeight
          }
          

          【讨论】:

            【解决方案14】:

            我的解决方案是在 tableview 将根据估计的偏移量减速之前添加单元格。它可以通过速度来预测。

            - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)offset {
            
                NSLog(@"offset: %f", offset->y+scrollView.frame.size.height);
                NSLog(@"Scroll view content size: %f", scrollView.contentSize.height);
            
                if (offset->y+scrollView.frame.size.height > scrollView.contentSize.height - 300) {
                    NSLog(@"Load new rows when reaches 300px before end of content");
                    [[DataManager shared] fetchRecordsNextPage];
                }
            }
            

            【讨论】:

              【解决方案15】:

              Swift 3 更新

              Neoneye 的答案在 Objective C 中最适合我,这相当于 Swift 3 中的答案:

              func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
                  let offset: CGPoint = scrollView.contentOffset
                  let bounds: CGRect = scrollView.bounds
                  let size: CGSize = scrollView.contentSize
                  let inset: UIEdgeInsets = scrollView.contentInset
                  let y: CGFloat = offset.y + bounds.size.height - inset.bottom
                  let h: CGFloat = size.height
              //        print("offset: %f", offset.y)
              //        print("content.height: %f", size.height)
              //        print("bounds.height: %f", bounds.size.height)
              //        print("inset.top: %f", inset.top)
              //        print("inset.bottom: %f", inset.bottom)
              //        print("position: %f of %f", y, h)
              
                  let reloadDistance: CGFloat = 10
              
                  if (y > h + reloadDistance) {
                          print("load more rows")
                  }
              }
              

              【讨论】:

                【解决方案16】:

                我想对我的任何 1 个完整的 Tableviewcell 执行一些操作。

                所以代码是链接:

                -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
                {
                    NSArray* cells = self.tableView.visibleCells;
                    NSIndexPath *indexPath = nil ;
                
                    for (int aIntCount = 0; aIntCount < [cells count]; aIntCount++)
                    {
                
                        UITableViewCell *cell = [cells objectAtIndex:aIntCount];
                CGRect cellRect = [self.tableView convertRect:cell.frame toView:self.tableView.superview];
                
                        if (CGRectContainsRect(self.tableView.frame, cellRect))
                        {
                            indexPath = [self.tableView indexPathForCell:cell];
                
                    //  remain logic
                        }
                     }
                }
                

                希望这对某人有所帮助。

                【讨论】:

                  【解决方案17】:

                  @neoneye 的回答对我有用。这是它的 Swift 4 版本

                      let offset = scrollView.contentOffset
                      let bounds = scrollView.bounds
                      let size = scrollView.contentSize
                      let insets = scrollView.contentInset
                      let y = offset.y + bounds.size.height - insets.bottom
                      let h = size.height
                      let reloadDistance = CGFloat(10)
                      if y > h + reloadDistance {
                          //load more rows
                      }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2017-06-26
                    • 2019-10-12
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-07-22
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-02-15
                    相关资源
                    最近更新 更多