如何知道UITableView何时滚动到iPhone的底部


100

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

有谁知道这一点,请帮助我,在此先感谢!

Answers:


18

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

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point

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


不幸的是,我的应用程序将实时更新该表中现有行的数据,因此当表完全不滚动时,这种方式可能会获得更多内容。
孙阮,

247

在tableview委托中做这样的事情

对象:

- (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)。
克里斯·普林斯

4
每当用户在屏幕上上下移动手指时,“ scrollViewDidScroll”中的该代码就会执行。最好将其移动到“ scrollViewDidEndDecelerating”下。这样,当用户停止移动手指时将执行一次。
Misha 2015年

嗯..此代码仍然有效?没有让我的UITableView的底部。我希望我知道以上所有代码背后的原因,以便我可以解决
FlowUI。SimpleUITesting.com

偏移量:237.000000 content.height:855.000000 bounds.height:667.000000 inset.top:64.000000 inset.bottom:49.000000 pos:855.000000 of 855.000000(如果是假的话)
Abhishek Thapliyal

62

修改后的新生儿回答了一下。

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

当从某些内容提供商(Web服务,核心数据等)加载更多内容时适用。请注意,这种方法不考虑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返回数据,也会发生这种情况。
教务长

2
院长,问题是关于知道表格视图何时滚动到底部。您是否从API提取数据无关紧要,不是吗?
眼球

但是没有消息显示负载更多..这样用户可以知道还有更多结果要显示。
iPhone 7年7

在我的情况下,好的答案是可行的:float float reload_distance = 10; if(y>(h-reload_distance)){NSLog(@“加载更多行”); }因为y = 565,而h也是565
阿卜舍舍克·萨普利雅尔

1
我尝试了Eyeball和@neoneye的答案。相对于“ scrollViewDidEndDragging”,信不信由你的“ scrollViewDidScroll”被调用了多次。所以使用'scrollViewDidEndDragging'是高效的,因为我对其有API调用。
Vinod Supnekar,

39

在以下位置添加此方法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");
    }
}

3
除了一个小细节,我喜欢这种解决方案。if(distanceFromBottom <= height)
Mark McCorkle

这帮助我解决了我的问题,谢谢!!标签栏!这是一个愚蠢的标签栏!
Dmytro

这项工作就像一种魅力,而且也很简单,但是我遇到了一个小问题,例如它在最后一行执行了两次或三次。如何使其到达tableview的最后一行时仅执行一次?
R. Mohan

非常感谢!!我将此代码放在scrollViewWillBeginDecelerating中,并且滚动到最后一行时仅执行一次。
马纳利

20

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

- (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”的来源吗?
ainesophaur

这是用于滚动视图而不是表格
iosMentalist 2014年

19

使用– 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的数据,则将陷入无限循环。
Dielson Sales's

14

UITableView是的子类UIScrollView,并UITableViewDelegate符合UIScrollViewDelegate。因此,您附加到表格视图的委托将获得诸如的事件scrollViewDidScroll:,并且您可以contentOffset在表格视图上调用诸如之类的方法来查找滚动位置。


是的,这就是我要查找的内容,通过实现该委托并检查滚动位置是否为UITableViewScrollPositionBottom,我将知道表格何时滚动至底部,非常感谢
Son Nguyen

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

漂亮又简单


8

Swift你可以做这样的事情。每当您到达表视图的末尾时,以下条件将成立

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

1
问题是当tableview只有3个单元格时,例如,println("came to last row")此代码运行!
Mc.Lover

@ Mc.Lover对我来说是确切的问题,其CPU使用率将达到92%。neoneye的回答对我有用。如果需要,我还为其添加了快速版本。
阿努兰·巴曼

7

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

目标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!");
  }
}

斯威夫特2.x

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

5

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

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

1
这是错误的。每次您调用reloadData时,都会发出一个请求。有时您只需要重新加载表即可。
Patrick Bassut 2015年

您想说的是,如果您在最后一个单元格中又做了一次重载数据,那么会发生这种情况吗?
谢赫·里亚兹

5

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
}

5

这是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
        }
    }

3

我的解决方案是在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];
    }
}

3

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")
    }
}

2

我想对任何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
        }
     }
}

可能这对某些人有帮助。


0

@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
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.