UITableView가 iPhone에서 맨 아래로 스크롤되었는지 확인하는 방법


100

UITableView더 많은 콘텐츠를로드하고 표시하기 위해 맨 아래로 스크롤 한시기를 알고 싶습니다. 대리자 또는 테이블이 맨 아래로 스크롤 된시기를 컨트롤러에 알리는 다른 항목과 같은 것입니다.

누구든지 이것을 알고 있습니까, 제발 도와주세요, 미리 감사드립니다!

답변:


18

가장 좋은 방법은 화면 하단에있는 지점을 테스트하고 사용자가 스크롤 할 때마다이 메서드 호출을 사용하는 것입니다 ( scrollViewDidScroll).

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point

화면 하단 근처의 지점을 테스트 한 다음 반환되는 indexPath를 사용하여 해당 indexPath가 마지막 행인지 확인한 다음 해당하는 경우 행을 추가합니다.


불행히도 내 앱은이 테이블의 기존 행에 대한 데이터를 실시간으로 업데이트하므로 테이블이 전혀 스크롤되지 않을 때 더 많은 콘텐츠를 얻을 수 있습니다.
Son Nguyen

247

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).
Chris Prince 14

4
"scrollViewDidScroll"의이 코드는 사용자가 화면에서 손가락을 위 / 아래로 움직일 때마다 실행됩니다. "scrollViewDidEndDecelerating"아래로 이동하는 것이 좋습니다. 이렇게하면 사용자가 손가락 이동을 멈출 때 한 번 실행됩니다.
Misha

흠 ..이 코드는 여전히 작동합니까? 나를 위해 UITableView의 바닥을 얻지 못했습니다. 위의 모든 코드 뒤에있는 이유를 알았 으면
좋겠어요.

오프셋 : 237.000000 content.height : 855.000000 bounds.height : 667.000000 inset.top : 64.000000 inset.bottom : 49.000000 pos : 855.000000 of 855.000000 if is getting false
Abhishek Thapliyal

62

수정 된 neoneyes가 약간 대답합니다.

이 답변 은 손가락을 뗄마다 이벤트가 한 번만 트리거되기를 원하는 사용자를 대상 으로합니다 .

일부 콘텐츠 제공 업체 (웹 서비스, 핵심 데이터 등)에서 더 많은 콘텐츠를로드 할 때 적합합니다. 이 접근 방식은 웹 서비스의 응답 시간을 고려하지 않습니다.

- (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
Dean, 질문은 테이블 뷰가 언제 아래로 스크롤되는지 아는 것이 었습니다. API에서 데이터를 가져 오는지 여부는 무관하지 않습니까?
Eyeball

그러나 더 많은로드를 표시하는 메시지는 없습니다. 표시 할 결과가 더 있음을 사용자가 알 수 있습니다.
iPhone 7

제 경우에 좋은 대답은 다음과 같습니다. float reload_distance = 10; if (y> (h-reload_distance)) {NSLog (@ "load more rows"); } y = 565이고 h도 565이기 때문에
Abhishek Thapliyal

1
나는 Eyeball과 @neoneye의 대답을 모두 시도했습니다 .'scrollViewDidEndDragging '에 비해'scrollViewDidScroll '이 여러 번 호출되었습니다. 그래서 API 호출이 있으므로 'scrollViewDidEndDragging'을 사용하는 것이 효율적이었습니다.
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 2013 년

이것은 내 문제를 해결하는 데 도움이되었습니다. 감사합니다 !! 탭바 !! 멍청한 탭바였습니다 !!
Dmytro

이 작품은 매력적이며 단순하지만 마지막 줄에 2 ~ 3 회 실행하는 것과 같은 작은 문제가 하나 있습니다. tableview의 마지막 행에 도달했을 때 한 번만 실행되도록 만드는 방법은 무엇입니까?
R. 모한

정말 고맙습니다!! 이 코드를 scrollViewWillBeginDecelerating에 넣고 마지막 행으로 스크롤 할 때 한 번만 실행됩니다.
Manali

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 2013

이것은 테이블이 아니라 스크롤보기 용입니다.
iosMentalist 2014-09-22

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

14

UITableView(A)의 서브 클래스 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이 같은 작업을 수행 할 수 있습니다. tableview 끝에 도달 할 때마다 다음 조건이 참입니다.

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 2011

@ Mc.Lover는 CPU 사용량이 92 %가되는 저에게 정확한 문제였습니다. neoneye의 답변이 저에게 효과적이었습니다. 필요한 경우 신속한 버전도 추가했습니다.
Anuran Barman

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 년

마지막 셀에서 데이터를 다시로드하면 이런 일이 발생합니까?
Shaik Riyaz

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

다음은 신속한 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
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.