web-dev-qa-db-ja.com

ListViewで上スクロールと下スクロールを検出

次の要件があります。

  • 最初に、ページ番号2のデータがサーバーから取得され、アイテムがListViewに入力されます。

シナリオで前のページと次のページの両方が使用できることを考慮して、次のコードが追加されました。

 if(prevPageNo > 0){
    mListViewActual.setOnScrollListener(this);
 }

 if(nextPageNo > 0){
    mListViewActual.setOnScrollListener(this);
 }

次の方法でスクロールアップおよびスクロールダウンを検出するには、どのような条件を設定する必要がありますか。

  1. void onScroll(AbsListViewビュー、int firstVisibleItem、int visibleItemCount、int totalItemCount)
  2. void onScrollStateChanged(AbsListViewビュー、int scrollState)

アクション:スクロールアップとスクロールダウンが検出された後、前のページnoまたは次のページnoのいずれかでサービスが呼び出され、リストビューに入力されるアイテムを取得します。

任意の入力が役立ちます。

以下のリンクをたどりましたが、正しいスクロールアップ/スクロールダウンアクションが返されません。

リンク1リンク2

68
chiranjib

setOnScrollListenerを使用してみて、scrollStateでonScrollStateChangedを実装してください

setOnScrollListener(new OnScrollListener(){
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      // TODO Auto-generated method stub
    }
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      // TODO Auto-generated method stub
      final ListView lw = getListView();

       if(scrollState == 0) 
      Log.i("a", "scrolling stopped...");


        if (view.getId() == lw.getId()) {
        final int currentFirstVisibleItem = lw.getFirstVisiblePosition();
         if (currentFirstVisibleItem > mLastFirstVisibleItem) {
            mIsScrollingUp = false;
            Log.i("a", "scrolling down...");
        } else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
            mIsScrollingUp = true;
            Log.i("a", "scrolling up...");
        }

        mLastFirstVisibleItem = currentFirstVisibleItem;
    } 
    }
  });
90
Sunil Kumar

上に示したソリューションのいくつかからの作業修正バージョンがあります。

別のクラスListViewを追加します。

package com.example.view;

import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.View;
import Android.widget.AbsListView;

public class ListView extends Android.widget.ListView {

    private OnScrollListener onScrollListener;
    private OnDetectScrollListener onDetectScrollListener;

    public ListView(Context context) {
        super(context);
        onCreate(context, null, null);
    }

    public ListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        onCreate(context, attrs, null);
    }

    public ListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        onCreate(context, attrs, defStyle);
    }

    @SuppressWarnings("UnusedParameters")
    private void onCreate(Context context, AttributeSet attrs, Integer defStyle) {
        setListeners();
    }

    private void setListeners() {
        super.setOnScrollListener(new OnScrollListener() {

            private int oldTop;
            private int oldFirstVisibleItem;

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (onScrollListener != null) {
                    onScrollListener.onScrollStateChanged(view, scrollState);
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (onScrollListener != null) {
                    onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
                }

                if (onDetectScrollListener != null) {
                    onDetectedListScroll(view, firstVisibleItem);
                }
            }

            private void onDetectedListScroll(AbsListView absListView, int firstVisibleItem) {
                View view = absListView.getChildAt(0);
                int top = (view == null) ? 0 : view.getTop();

                if (firstVisibleItem == oldFirstVisibleItem) {
                    if (top > oldTop) {
                        onDetectScrollListener.onUpScrolling();
                    } else if (top < oldTop) {
                        onDetectScrollListener.onDownScrolling();
                    }
                } else {
                    if (firstVisibleItem < oldFirstVisibleItem) {
                        onDetectScrollListener.onUpScrolling();
                    } else {
                        onDetectScrollListener.onDownScrolling();
                    }
                }

                oldTop = top;
                oldFirstVisibleItem = firstVisibleItem;
            }
        });
    }

    @Override
    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    public void setOnDetectScrollListener(OnDetectScrollListener onDetectScrollListener) {
        this.onDetectScrollListener = onDetectScrollListener;
    }
}

そしてインターフェース:

public interface OnDetectScrollListener {

    void onUpScrolling();

    void onDownScrolling();
}

最後に使用方法:

com.example.view.ListView listView = (com.example.view.ListView) findViewById(R.id.list);
listView.setOnDetectScrollListener(new OnDetectScrollListener() {
    @Override
    public void onUpScrolling() {
        /* do something */
    }

    @Override
    public void onDownScrolling() {
        /* do something */
    }
});

XMLレイアウトで:

<com.example.view.ListView
    Android:id="@+id/list"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"/>

これは私の最初のトピックです、私を厳しく判断しないでください。 =)

63
maXp

これは簡単な実装です:

lv.setOnScrollListener(new OnScrollListener() {
        private int mLastFirstVisibleItem;

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {

        }

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

            if(mLastFirstVisibleItem<firstVisibleItem)
            {
                Log.i("SCROLLING DOWN","TRUE");
            }
            if(mLastFirstVisibleItem>firstVisibleItem)
            {
                Log.i("SCROLLING UP","TRUE");
            }
            mLastFirstVisibleItem=firstVisibleItem;

        }
    });

さらに精度が必要な場合は、このカスタムListViewクラスを使用できます。

import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.View;
import Android.widget.AbsListView;
import Android.widget.ListView;

/**
 * Created by root on 26/05/15.
 */
public class ScrollInterfacedListView extends ListView {


    private OnScrollListener onScrollListener;
    private OnDetectScrollListener onDetectScrollListener;

    public ScrollInterfacedListView(Context context) {
        super(context);
        onCreate(context, null, null);
    }

    public ScrollInterfacedListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        onCreate(context, attrs, null);
    }

    public ScrollInterfacedListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        onCreate(context, attrs, defStyle);
    }

    @SuppressWarnings("UnusedParameters")
    private void onCreate(Context context, AttributeSet attrs, Integer defStyle) {
        setListeners();
    }

    private void setListeners() {
        super.setOnScrollListener(new OnScrollListener() {

            private int oldTop;
            private int oldFirstVisibleItem;

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (onScrollListener != null) {
                    onScrollListener.onScrollStateChanged(view, scrollState);
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (onScrollListener != null) {
                    onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
                }

                if (onDetectScrollListener != null) {
                    onDetectedListScroll(view, firstVisibleItem);
                }
            }

            private void onDetectedListScroll(AbsListView absListView, int firstVisibleItem) {
                View view = absListView.getChildAt(0);
                int top = (view == null) ? 0 : view.getTop();

                if (firstVisibleItem == oldFirstVisibleItem) {
                    if (top > oldTop) {
                        onDetectScrollListener.onUpScrolling();
                    } else if (top < oldTop) {
                        onDetectScrollListener.onDownScrolling();
                    }
                } else {
                    if (firstVisibleItem < oldFirstVisibleItem) {
                        onDetectScrollListener.onUpScrolling();
                    } else {
                        onDetectScrollListener.onDownScrolling();
                    }
                }

                oldTop = top;
                oldFirstVisibleItem = firstVisibleItem;
            }
        });
    }

    @Override
    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    public void setOnDetectScrollListener(OnDetectScrollListener onDetectScrollListener) {
        this.onDetectScrollListener = onDetectScrollListener;
    }


    public interface OnDetectScrollListener {

        void onUpScrolling();

        void onDownScrolling();
    }

}

使用例:(layout.xmlにXmlタグとして追加することを忘れないでください)

scrollInterfacedListView.setOnDetectScrollListener(new ScrollInterfacedListView.OnDetectScrollListener() {
            @Override
            public void onUpScrolling() {
               //Do your thing
            }

            @Override
            public void onDownScrolling() {

             //Do your thing
            }
        });
44
Gal Rom

すべてのメソッドがポストされると、ユーザーが最初の要素から上にスクロールするのか、最後から下にスクロールするのかを認識するのに問題があります。スクロールの上下を検出する別のアプローチを次に示します。

        listView.setOnTouchListener(new View.OnTouchListener() {
            float height;
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                float height = event.getY();
                if(action == MotionEvent.ACTION_DOWN){
                    this.height = height;
                }else if(action == MotionEvent.ACTION_UP){
                    if(this.height < height){
                        Log.v(TAG, "Scrolled up");
                    }else if(this.height > height){
                        Log.v(TAG, "Scrolled down");
                    }
                }
                return false;
            }
        });
10
Javier Carmona
            ListView listView = getListView();
            listView.setOnScrollListener(new OnScrollListener() {

                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {

                    view.setOnTouchListener(new OnTouchListener() {
                        private float mInitialX;
                        private float mInitialY;

                        @Override
                        public boolean onTouch(View v, MotionEvent event) {
                            switch (event.getAction()) {
                                case MotionEvent.ACTION_DOWN:
                                    mInitialX = event.getX();
                                    mInitialY = event.getY();
                                    return true;
                                case MotionEvent.ACTION_MOVE:
                                    final float x = event.getX();
                                    final float y = event.getY();
                                    final float yDiff = y - mInitialY;
                                    if (yDiff > 0.0) {
                                        Log.d(tag, "SCROLL DOWN");
                                        scrollDown = true;
                                        break;

                                    } else if (yDiff < 0.0) {
                                        Log.d(tag, "SCROLL up");
                                        scrollDown = true;
                                        break;

                                    }
                                    break;
                            }
                            return false;
                        }
                    });
10
user1467024

私のソリューションは完全に機能し、スクロール方向ごとに正確な値を提供します。 distanceFromFirstCellToTopには、最初のセルから親ビューの最上部までの正確な距離が含まれます。この値をpreviousDistanceFromFirstCellToTopに保存し、スクロールしながら新しい値と比較します。低い場合は上にスクロールし、そうでない場合は下にスクロールします。

private int previousDistanceFromFirstCellToTop;

listview.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        View firstCell = listview.getChildAt(0);
        int distanceFromFirstCellToTop = listview.getFirstVisiblePosition() * firstCell.getHeight() - firstCell.getTop();

        if(distanceFromFirstCellToTop < previousDistanceFromFirstCellToTop)
        {
           //Scroll Up
        }
        else if(distanceFromFirstCellToTop  > previousDistanceFromFirstCellToTop)
        {
           //Scroll Down
        }
        previousDistanceFromFirstCellToTop = distanceFromFirstCellToTop;
    }
});

Xamarin開発者向けのソリューションは次のとおりです。

注:UIスレッドで実行することを忘れないでください

listView.Scroll += (o, e) =>
{
    View firstCell = listView.GetChildAt(0);
    int distanceFromFirstCellToTop = listView.FirstVisiblePosition * firstCell.Height - firstCell.Top;

    if (distanceFromFirstCellToTop < previousDistanceFromFirstCellToTop)
    {
        //Scroll Up
    }
    else if (distanceFromFirstCellToTop > previousDistanceFromFirstCellToTop)
    {
        //Scroll Down
    }
    previousDistanceFromFirstCellToTop = distanceFromFirstCellToTop;
};
8
da Rocha Pires

より大きな要素でのスクロールも検出するには、onTouch Listenerを好みます。

listview.setOnTouchListener(new View.OnTouchListener() {

        int scrollEventListSize = 5; 
        float lastY;
        // Used to correct for occasions when user scrolls down(/up) but the onTouchListener detects it incorrectly. We will store detected up-/down-scrolls with -1/1 in this list and evaluate later which occured more often
        List<Integer> downScrolledEventsHappened;

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            float diff = 0;
            if(event.getAction() == event.ACTION_DOWN){
                lastY = event.getY();
                downScrolledEventsHappened = new LinkedList<Integer>();
            }
            else if(event.getAction() == event.ACTION_MOVE){
                diff = event.getY() - lastY;
                lastY = event.getY();

                if(diff>0)
                    downScrolledEventsHappened.add(1);
                else 
                    downScrolledEventsHappened.add(-1);

               //List needs to be filled with some events, will happen very quickly
                if(downScrolledEventsHappened.size() == scrollEventListSize+1){
                    downScrolledEventsHappened.remove(0);
                    int res=0;
                    for(int i=0; i<downScrolledEventsHappened.size(); i++){
                        res+=downScrolledEventsHappened.get(i);
                    }

                    if (res > 0) 
                        Log.i("INFO", "Scrolled up");
                    else 
                        Log.i("INFO", "Scrolled down");
                }
            }
            return false; // don't interrupt the event-chain
        }
    });
4
AljoSt

このはるかに単純なソリューションを使用しました。

setOnScrollListener( new OnScrollListener() 
{

    private int mInitialScroll = 0;

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

        boolean scrollUp = scrolledOffset > mInitialScroll;
        mInitialScroll = scrolledOffset;
    }


    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {


    }

}
4
Vaiden

リストビューにスクロールリスナーを設定するだけです。

ヘッダーまたはフッターがある場合は、表示カウントも確認する必要があります。増加する場合、下にスクロールしていることを意味します。 (ヘッダーの代わりにフッターがある場合は逆にします)

リストビューにヘッダーまたはフッターがない場合は、表示されているアイテム数をチェックする行を削除できます。

listView.setOnScrollListener(new AbsListView.OnScrollListener() {
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if (mLastFirstVisibleItem > firstVisibleItem) {
                Log.e(getClass().toString(), "scrolling up");
            } else if (mLastFirstVisibleItem < firstVisibleItem) {
                Log.e(getClass().toString(), "scrolling down");
            } else if (mLastVisibleItemCount < visibleItemCount) {
                Log.e(getClass().toString(), "scrolling down");
            } else if (mLastVisibleItemCount > visibleItemCount) {
                Log.e(getClass().toString(), "scrolling up");
            }
            mLastFirstVisibleItem = firstVisibleItem;
            mLastVisibleItemCount = visibleItemCount;
        }

        public void onScrollStateChanged(AbsListView listView, int scrollState) {
        }
    });

そして、この変数を持っています

int mLastFirstVisibleItem;
int mLastVisibleItemCount;
3
eluleci

FirstVisibleItemを保存し、次のonScrollチェックで、新しいfirstVisibleItemが前のものよりも小さいか大きいかを確認します。

擬似コードの例(テストされていません):

int lastVisibleItem = 0;
boolean isScrollingDown = false;

void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (firstVisibleItem > lastVisibleItem) {
        isScrollingDown = true;
    }
    else {
        isScrollingDown = false;
    }
    lastVisibleItem = firstVisibleItem;
}
3
thiagolr

何らかの理由でAndroidのドキュメントはこれをカバーしておらず、使用されているメソッドはドキュメント内でもありません...見つけるのに時間がかかりました。

スクロールが上部にあるかどうかを検出するには、これを使用します。

public boolean checkAtTop() 
{
    if(listView.getChildCount() == 0) return true;
    return listView.getChildAt(0).getTop() == 0;
}

これにより、スクローラーが上部にあるかどうかが確認されます。今、一番下にそれをするために、あなたが持っている子供の数をそれに渡して、その数に対してチェックする必要があります。一度に画面に表示される人数を把握し、それを子供の数から差し引く必要があるかもしれません。私はそれをする必要がなかった。お役に立てれば

1
Shaun

Android listviewのスクロールアップ/ダウンを検出する簡単な方法

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount){
  if(prevVisibleItem != firstVisibleItem){
    if(prevVisibleItem < firstVisibleItem)
      //ScrollDown
    else
      //ScrollUp

  prevVisibleItem = firstVisibleItem;
}

忘れないで

yourListView.setOnScrollListener(yourScrollListener);
1
Rick Royd Aban

リストビューでスクロールの上下を検出するトリックは、ListViewのOnS​​crollListenerのonScroll関数でこの関数を呼び出すだけです。

private int oldFirstVisibleItem = -1;
    private protected int oldTop = -1;
    // you can change this value (pixel)
    private static final int MAX_SCROLL_DIFF = 5;

    private void calculateListScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (firstVisibleItem == oldFirstVisibleItem) {
            int top = view.getChildAt(0).getTop();
            // range between new top and old top must greater than MAX_SCROLL_DIFF
            if (top > oldTop && Math.abs(top - oldTop) > MAX_SCROLL_DIFF) {
                // scroll up
            } else if (top < oldTop && Math.abs(top - oldTop) > MAX_SCROLL_DIFF) {
                // scroll down
            }
            oldTop = top;
        } else {
            View child = view.getChildAt(0);
            if (child != null) {
                oldFirstVisibleItem = firstVisibleItem;
                oldTop = child.getTop();
            }
        }
    }
1
thanhlcm

ListViewのセルサイズが大きいいくつかの例を使用して問題が発生しました。それで、あなたの指のわずかな動きを検出する私の問題の解決策を見つけました。私は可能な限り最小限に単純化しており、次のとおりです。

private int oldScrolly;


@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

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

            View view = absListView.getChildAt(0);
            int scrolly = (view == null) ? 0 : -view.getTop() + absListView.getFirstVisiblePosition() * view.getHeight();
            int margin = 10;

            Log.e(TAG, "Scroll y: " + scrolly + " - Item: " + firstVisibleItem);


            if (scrolly > oldScrolly + margin) {
                Log.d(TAG, "SCROLL_UP");
                oldScrolly = scrolly;
            } else if (scrolly < oldScrolly - margin) {
                Log.d(TAG, "SCROLL_DOWN");
                oldScrolly = scrolly;
            }
        }
    });

PD:MARGINを使用して、そのマージンを満たすまでスクロールを検出しません。これにより、ビューを表示または非表示にするときの問題を回避し、ビューの点滅を回避します。

0

私が最初に試すことは次のとおりです。

1)次のメソッドを使用してインターフェイスを作成します(OnScrollTopOrBottomListenerと呼びます)。

void onScrollTop();

void onScrollBottom();

2)リストのアダプターに、作成したインターフェイスとして入力されたメンバーインスタンスを追加し、セッターとゲッターを提供します。

3)アダプターのgetView()実装で、positionパラメーターが0またはgetCount()-1であるかどうかを確認します。OnScrollTopOrBottomListenerインスタンスがnullでないことも確認します。

4)位置が0の場合、onScrollTopOrBottomListener.onScrollTop()を呼び出します。位置がgetCount()-1の場合、onScrollTopOrBottomListener.onScrollBottom()を呼び出します。

5)OnScrollTopOrBottomListenerの実装で、適切なメソッドを呼び出して目的のデータを取得します。

それが何らかの形で役立つことを願っています。

-ブランドン

0
Brandon