42

いくつかのアイテムをListView表示しています。のスクロールListView方法に応じて、の表示部分に現在表示されているアイテムに対して操作を実行したいと思います。ListViewしたがって、私はのを実装することを考えましOnScrollListenerListView。Android apiリファレンスによると、onScrollメソッドは「スクロールが完了した後に呼び出されます」。スクロールが完了したら、アクションを実行するので、これは私が必要としていたことのようにListView思えます(onScrollメソッドは、最初に表示されたアイテムのインデックスと表示されたアイテムの数を返します)。

しかし、一度実装するLogCatと、onScrollメソッドは、スクロールが完了すると起動されるだけでなく、スクロールの最初から最後まで、表示ビューに入るすべての新しいアイテムに対して起動されることがわかります。これは私が期待する行動でも必要な行動でもありません。代わりに、リスナーのもう1つのメソッド(onScrollStateChanged)は、に現在表示されているアイテムに関する情報を提供しませんListView

では、この2つの方法を使用して、スクロールの終了を検出し、表示されたアイテムに関する情報を取得する方法を知っている人はいますか?API参照とメソッドの実際の動作との間の不整合は、私を少し混乱させました。前もって感謝します。

PS:似たようなトピックをいくつか見てきましたが、全体がどのように機能するかを理解するのに役立つものは何もありません。

4

9 に答える 9

54

結局、私はそれほどエレガントではない解決策に到達しましたが、それは私にとってはうまくいきました。onScrollメソッドがスクロールの最後で呼び出されるのではなく、スクロールのすべてのステップで呼び出され、onScrollStateChangedが実際にはスクロールが完了したときにのみ呼び出されることを理解したので、次のようにします。

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    this.currentFirstVisibleItem = firstVisibleItem;
    this.currentVisibleItemCount = visibleItemCount;
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    this.currentScrollState = scrollState;
    this.isScrollCompleted();
 }

private void isScrollCompleted() {
    if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) {
        /*** In this way I detect if there's been a scroll which has completed ***/
        /*** do the work! ***/
    }
}

実際には、ListViewがスクロールされるたびに、最初の表示アイテムと表示アイテム数に関するデータを保存します(onScrollメソッド)。スクロールの状態が変化したとき(onScrollStateChanged)状態を保存し、スクロールがあったかどうか、およびスクロールが完了したかどうかを実際に理解する別のメソッドを呼び出します。このようにして、必要な表示アイテムに関するデータも取得します。たぶんきれいではありませんが、動作します!

よろしく

于 2011-06-17T10:46:33.297 に答える
13
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
  int visibleItemCount, int totalItemCount) {

  if (list.getLastVisiblePosition() == list.getAdapter().getCount() - 1
      && list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) {
    // Scroll end reached
    // Write your code here
  }
}
于 2013-09-13T07:21:01.590 に答える
9
@Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {

            if((firstVisibleItem + visibleItemCount) ==  totalItemCount)
            {
                Log.i("Info", "Scroll Bottom" );
            }
        }});
于 2014-06-17T01:25:07.753 に答える
6

この振る舞いを下げるのは難しいので、完璧にするのにかなりの時間がかかりました。問題の核心は、私が知る限り、スクロールリスナーだけでは「スクロールストップ」(方向ボタン/トラックボールを含む)を検出するのに十分ではないということです。期待どおりに機能することを組み合わせて実行することになりました。

私ができると思った最善の方法は、ListViewを拡張し、いくつかのメソッドをオーバーライドすることでした。

  ....
  @Override
  public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) {
      startWait();
    }
    return super.onKeyUp(keyCode, event);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
      stopWait();
    }
    if (event.getAction() == MotionEvent.ACTION_UP ||
        event.getAction() == MotionEvent.ACTION_CANCEL) {
      startWait();
    }
    return super.onTouchEvent(event);
  }

  private OnScrollListener customScrollListener = new OnScrollListener() {
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
      int totalItemCount) {
      stopWait();
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
        startWait();
      } else {
        stopWait();
      }
    }
  };

  //All this waiting could be improved, but that's the idea
  private Thread waitThread = null;
  private int waitCount  = Integer.MIN_VALUE;

  public void stopWait() {
    waitCount = Integer.MIN_VALUE;
  }

  public synchronized void startWait() {
    waitCount = 0;

    if (waitThread != null) {
      return;
    }

    waitThread = new Thread(new Runnable() {
    @Override
    public void run() {
    try {
      for (; waitCount.get() < 10; waitCount++) {
        Thread.sleep(50);
      }

        //Kick it back to the UI thread.
        view.post(theRunnableWithYourOnScrollStopCode); // HERE IS WHERE YOU DO WHATEVER YOU WANTED TO DO ON STOP
      } catch (InterruptedException e) {
      } finally  {
        waitThread = null;
      }
    }
  });
  waitThread.start();
}

customScrollListenerコンストラクターでもバインドする必要があることに注意してください。この実装は、「イベント」をすぐには発生させないため、実際にスクロールが完全に停止するまで少し待機するので、便利だと思います。

于 2011-06-15T13:55:25.643 に答える
4

以前の回答を分析して、独自のものを見つけました:

onViewCreated、onCreate、またはリストビューを取得する場所:

ListView list = (ListView) view.findViewById(R.id.[your id]);
    list.setOnScrollListener(this);

次に、リスナーメソッドを入力します。

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
 // yes, just leave it empty
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    this.isScrollCompleted(view, scrollState);
 }

private void isScrollCompleted(AbsListView view, int scrollState) {
    if (!view.canScrollVertically(1) && this.currentScrollState == SCROLL_STATE_IDLE) {
        // do work
    }
}

どうやらそれがすべきことをしているようです:大量のコードやアダプタの変更なしでリストの終わりを検出します。

于 2015-12-25T15:57:32.847 に答える
3

これを試してください...

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                     int totalItemCount) {

    int position = firstVisibleItem+visibleItemCount;
    int limit = totalItemCount;

    // Check if bottom has been reached
    if (position >= limit && totalItemCount > 0) {
         //scroll end reached
          //Write your code here
    }
}
于 2015-04-21T06:49:28.993 に答える
3

e-calの答えのより有用な表現

リスナーの実装:

public abstract class OnScrollFinishListener implements AbsListView.OnScrollListener {

    int mCurrentScrollState;
    int mCurrentVisibleItemCount;

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        mCurrentScrollState = scrollState;
        if (isScrollCompleted()) {
            onScrollFinished();
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mCurrentVisibleItemCount = visibleItemCount;
    }

    private boolean isScrollCompleted() {
        return mCurrentVisibleItemCount > 0 && mCurrentScrollState == SCROLL_STATE_IDLE;
    }

    protected abstract void onScrollFinished();
}

使用法:

    listView.setOnScrollListener(new OnScrollFinishListener() {
         @Override
         protected void onScrollFinished() {
             // do whatever you need here!
         }
    });
于 2015-10-02T09:12:12.593 に答える
0

もう1つの簡単な解決策があります。リスナーをlistviewのアダプターに配置し、getviewでif(position == totalItemCount of items in array in display)をチェックします。はいの場合、アダプターからリスナーを呼び出し、リスナーで操作を実行します。

于 2013-04-18T08:57:01.913 に答える
0

リストがOnScrollListenerの一番下にあるかどうかを確認しようとすると、多くの問題が発生しました。私が見つけた最善の解決策は、現在最後の行を表示しているかどうかをアダプターのgetViewメソッドから確認することです。

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ActivityView view;
        if (convertView==null)
            view = (ActivityView)inflater.inflate(R.layout.activity_item, null);
        else
            view = (ActivityView)convertView;

       view.showRow(activitiesList.get(position),position,controller,this);
        if(position == activitiesList.size() - 1)
        {
            Log.i("BOTTOM","reached");
        }
        return view;
    }

そこで、最下部に到達したことをフラグメント/アクティビティに通知するためのインターフェイスを簡単に作成できます。

乾杯。

于 2015-05-06T03:04:19.537 に答える