iPhoneでUITableViewが下にスクロールしたときを知る方法


100

UITableViewテーブルを下にスクロールしたときにデリゲートなどのコンテンツをコントローラーに通知するために、追加のコンテンツを読み込んで表示するために、a が下にスクロールしたときを知りたいです。

誰かがこれを知っていますか、事前に感謝して私を助けてください!

回答:


18

最良の方法は、画面の下部のポイントをテストし、ユーザーがスクロールするとき(scrollViewDidScroll)にこのメソッド呼び出しを使用することです。

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point

画面の下部近くのポイントをテストしてから、indexPathを使用して、そのindexPathが最後の行であるかどうかを確認し、最後の行である場合は行を追加します。


残念ながら、私のアプリはこのテーブルの既存の行のデータをリアルタイムで更新するため、この方法では、テーブルがまったくスクロールされていないときに、より多くのコンテンツを取得できます。
Son Nguyen、

247

テーブルビューデリゲートで次のようなことを行います

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、

4
"scrollViewDidScroll"のこのコードは、ユーザーが画面上で指を上下に動かすたびに実行されます。「scrollViewDidEndDecelerating」の下に移動することをお勧めします。この方法では、ユーザーが指の移動を停止したときに1回実行されます。
ミシャ

うーん..このコードはまだ機能しますか?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の855.000000がfalseになる場合
Abhishek Thapliyal

62

変更された新人は少し答えます。

この回答は、指を離すごとに1回だけイベントがトリガーされるようにしたいユーザーを対象としています。

一部のコンテンツプロバイダー(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がデータを返すのを待っている場合でも発生します。
2014

2
ディーン、質問は、テーブルビューがいつ一番下までスクロールしたかを知ることでした。APIからデータをフェッチしているかどうかは関係ありませんか?
眼球2014

しかし、ユーザーは、表示する結果がまだあることに気づくことができるように、負荷がもっと多いことを示すメッセージはありません。
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、2018

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
このソリューションは、細かい点を1つ除いて気に入っています。if(distanceFromBottom <= height)
Mark McCorkle

これは私の問題のトラブルシューティングに役立ちました。ありがとうございます!! タブバー!! それは愚かなタブバーでした!!
Dmytro

この作品は魅力のようで、それも単純ですが、最後の行で2〜3回実行されるような小さな問題に直面しています。テーブルビューの最後の行に達したときに一度だけ実行する方法は?
R.モハン2017

どうもありがとうございます!!このコードをscrollViewWillBeginDeceleratingに配置し、最後の行にスクロールしたときに1回だけ実行されます。
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

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セールス、2016

14

UITableViewのサブクラスでありUIScrollView、にUITableViewDelegate準拠しUIScrollViewDelegateます。したがって、テーブルビューにアタッチしたデリゲートはなどのイベントを取得し、テーブルビューなどのscrollViewDidScroll:メソッドを呼び出し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];

素敵でシンプル


8

Swiftあなたはこのようなことをすることができます。テーブルビューの最後に到達するたびに、次の条件が真になります

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

1
問題は、テーブルビューに3つのセルしかない場合です。たとえば、println("came to last row")このコードは実行されます。
Mc.Lover 2017年

@ Mc.Loverは、CPU使用率が92%になる私にとって正確な問題でした。neoneyeの答えは私のために働いた。必要に応じて、Swiftバージョンも追加しました。
Anuran Barman

7

@Jay Mayuの答えを基にして、私はより良い解決策の1つだと感じました:

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

5

最後のセルが表示を開始するとき、私は通常これを使用してより多くのデータをロードします

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

1
これは間違っています。reloadDataを呼び出すたびに、リクエストが行われます。また、テーブルをリロードする必要がある場合もあります。
Patrick Bassut、2015年

あなたが言いたかったのですが、最後のセルにいて、リロードデータを作成すると、これが起こりますか?
Shaik Riyaz 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
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.