在ListView中检测向上滚动和向下滚动


71

我有以下要求:

  • 首先,从服务器获取第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 view,int scrollState)

在操作之后:检测到向上滚动和向下滚动,相应地,将调用上一页或下一页的服务,以提取要在Listview中填充的项目。

任何输入都会有所帮助。

通过以下链接,但未返回正确的向上滚动/向下滚动操作:

链接1 链接2

Answers:


94

尝试使用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;
    } 
    }
  });

2
如果要在scollState是之前确定滚动方向SCROLL_STATE_IDLE怎么办?就像scrollState是SCROLL_STATE_FLING或时SCROLL_STATE_TOUCH_SCROLL
toobsco42 2014年

4
什么对我来说是在OnScroll添加该代码不onScrollStateChanged工作
艾曼·马哈古卜

如果所有项目都可见,则将不起作用,例如您有2个项目,并且想要像whatsapp一样向上滚动以加载更多内容
Leres Aldtai

63

这是上述某些解决方案的有效修改版本。

添加另一个类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"/>

这是我的第一个话题,不要严厉地评判我。=)


这正是我想要的。奇迹般有效!+1!
Nari Kim Shin

这非常精确!!谢谢
Krit

1
为什么不扩展滚动侦听器而不是整个视图?仅扩展滚动事件的视图并不是一种很好的做法,尤其是在以后要附加新的滚动侦听器时……
mradzinski 2015年

46

这是一个简单的实现:

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();
    }

}

使用示例:(不要忘记将其作为Xml标签添加到您的layout.xml中)

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

            @Override
            public void onDownScrolling() {

             //Do your thing
            }
        });

它基本上不适用于小滚动。这实现了“一次一个”检测器。仅当您滚动“整个单元格”时才会触发。
Fattie 2014年

我相信这很完美(请记住,它是按单元而不是按像素的)。与下面的“四个测试”方法相比,我进行了广泛的测试(示例Elulici的答案)。希望它能帮助某人。
Fattie 2014年

1
简便的解决方案。
LJ威尔逊

大!完美的作品!
KinGPinG

我得到的最简单的解决方案,谢谢
Chintan Desai 2015年

12

在发布所有方法后,在识别用户何时从第一个元素向上滚动或从最后一个元素向下滚动时会出现问题。这是检测向上/向下滚动的另一种方法:

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

这是从listView子项阻止触摸还是单击?
Noor Hossain

我只想要那个,谢谢!
Noor Hossain

10
            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;
                        }
                    });

这实际上是最好的解决方案,因为所有其他解决方案都取决于当前和最后可见的项目。当依赖于列表项时,您还依赖于适配器,并且如果滚动并且适配器没有使下一项膨胀,则您不知道用户是向上还是向下滚动。
Koc 2014年

3
这确实是一个糟糕的解决方案,因为您每次都要在onScrollStateChanged上设置视图触摸侦听器,这会带来很多开销。
萨德,2014年

8

我的解决方案可以完美地给出每个滚动方向的准确值。 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;
};

1
好答案!我只需要添加一个检查firstCell是否为null(因为它可能发生,所以它还没有膨胀)。
peshkira 2015年

这是我发现有关检测滚动方向的最佳和最简单的答案!即使物品高度小或大也没错,它完美且稳定地工作。非常感谢你。顺便说一句,您可以将上一个DistanceFromFirstCellToTop变量放入内部匿名 OnScrollListener类中,以使其变得更好。
想两次编码一次

1
很好的解决方案!仅缺少一件事:View firstCell = view.getChildAt(0); 添加后:if(firstCell == null){ return; }
马克·卡扎科夫(Marz Kazakov)

4

只需将滚动侦听器设置为您的列表视图即可。

如果您有页眉或页脚,则还应该检查可见计数。如果增加,则表示您正在向下滚动。(如果没有页脚而不是页眉,则将其反转)

如果您的列表视图中没有任何页眉或页脚,则可以删除那些使可见项目计数不正确的行。

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;

仅当您移动“整个单元格”时,此方法才有效。它不会检测到微小的运动。它确实可靠地工作。请注意,它会在单元格边界超过屏幕底部(或包围任何内容)而不是顶部时触发。顺便说一下,杜德,我敢肯定你上下调了!
Fattie 2014年

我看不到此答案与更简单的方法(例如上面的GaiRom)之间的功能差异。我对角落情况等进行了广泛的测试。Eluleci是否有理由进行额外的比较?
Fattie 2014年

4

我使用了这个简单得多的解决方案:

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) {


    }

}

什么是computeVerticalScrollOffset?
Fattie 2014年

2
ListView中的受保护方法
Vaiden 2014年

感谢一百万的迅速反应。我似乎无法使用它:我只是得到“找不到符号...”,因此尝试了所有视图。computeVerticalScrollOffset(),myListView.computeVerticalScrollOffset(),然后在您的代码中调用它。抱歉,我是iOS的Android新手(我爱Android!)
Fattie 2014年

2
由于它是一种受保护的方法,因此您需要扩展ListView。
Vaiden 2014年

4

为了同时检测较大元素的滚动,我更喜欢使用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
        }
    });

3

存储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;
}

实现了以上代码。当用户滚动并到达ListView的最后一项时,将调用onScroll(),但当用户滚动到ScrollView的第一个可见项时,不会调用onScroll()。对于第一页,第一个可见项:0。如何处理这种情况?在两种情况下都将调用onScrollStateChanged()。
chiranjib

我有一个每次都会调用onScroll的代码!您确定您的监听器一直处于运行状态吗?无论任何情况,都设置mListViewActual.setOnScrollListener(this)!
thiagolr

我没有任何条件地添加了mListViewActual.setOnScrollListener(this)。当用户尝试向上滚动时,即在这种情况下超出顶部可见项(在这种情况下为0)时,仍不会调用onScroll()。当前,如前所述,用户位于页面编号:2.仅在用户尝试滚动时向上,即,超出第一个可见项和onScroll()的调用,可以对服务器进行下一个服务调用以获取第1页的数据:
chiranjib,2013年

1

由于某种原因,Android文档没有涵盖这一点,并且甚至在文档中使用的方法也不是...我花了一段时间才找到它。

要检测滚动条是否位于顶部,可以使用它。

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

这将检查滚动条是否在顶部。现在,为了在底部进行操作,您必须将其拥有的子代数传递给它,然后对照该数字进行核对。您可能必须一次找出屏幕上有多少个,然后从孩子数量中减去。我从来没有这样做。希望这可以帮助


1

这些方法不能用于直接检测滚动方向。有很多方法可以指示方向。下面说明一种此类方法的简单代码(未经测试):

公共类ScrollTrackingListView扩展ListView {

    私有布尔值readyForMeasurement = false;
    private Boolean isScrollable = null;
    私有浮点数prevDistanceToEnd = -1.0;
    私有ScrollDirectionListener侦听器= null;

    public Sc​​rollTrackingListView(Context context){
        超级(上下文);
        在里面();
    }

    public Sc​​rollTrackingListView(Context context,AttributeSet attrs){
        超级(上下文,attrs);
        在里面();
    }

    public Sc​​rollTrackingListView(Context context,AttributeSet attrs,int defStyle){
        超级(上下文,属性,defStyle);
        在里面();
    }

    私人无效init(){
        ViewTreeObserver观察者= getViewTreeObserver();
        reader.addOnGlobalLayoutListener(globalLayoutListener);
        setOnScrollListener(scrollListener);
    }

    私有ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener
            = new ViewTreeObserver.OnGlobalLayoutListener(){

        @Override
        public void onGlobalLayout(){
            readyForMeasurement = true;
            computeDistanceToEnd();
        }

    };

    公共无效registerScrollDirectionListener(ScrollDirectionListener监听器){
        scrollDirectionListener =侦听器;
    }

    公共无效unregisterScrollDirectionListener(){
        scrollDirectionListener = null;
    }

    私人OnScrollListener scrollListener
            = new OnScrollListener(){

        @Override
        公共无效onScrollStateChanged(AbsListView absListView,int i){
            computeDistanceToEnd();
        }

        @Override
        公共无效onScroll(AbsListView absListView,int i,int i1,int i2){
            // 没做什么
        }

    };

    私人无效的calculateDistanceToEnd(){

        如果(readyForMeasurement){

            //我使用的是布局的高度,水平滚动条和
            //内容以及向下滚动的偏移量

            // computeVerticalScrollExtent用于计算滚动条轨道内的拇指长度。
            //拇指的长度是视图高度和内容长度的函数。
            int verticalScrollExtent = computeVerticalScrollExtent();
            int verticalScrollOffset = computeVerticalScrollOffset();
            int verticalScrollRange = computeVerticalScrollRange();
            int horizo​​ntalScrollBarHeight = getHorizo​​ntalScrollbarHeight();

            / **
             * 1.令“ R”代表垂直滚动条的范围。这对应于内容的长度
             *在视图中。
             * 2.令“ E”代表垂直滚动条的范围。范围是一个恒定值,并且是
             *(可能)等于与视图高度成比例的值。
             * 3.偏移“ o”表示用户可见范围内的当前位置。可能需要
             *值从“ 0到E”。
             *
             *现在,使用以下三个值来计算DistanceToEnd:
             *
             * DistanceToEnd =(R-o)/ E
             *
             * DistanceToEnd将以NumberOfScreenToEnd单位保存值。
             *
             * /

            float distanceToEnd =
                    ((float)(verticalScrollRange-verticalScrollOffset))/((float)(verticalScrollExtent));

            if(prevDistanceToEnd == -1){
                 prevDistanceToEnd = distanceToEnd;
            }其他{
                 if(listener!= null){
                     if(distanceToEnd> prevDistanceToEnd){
                        //用户向上滚动
                         listener.onScrollingUp();
                     }其他{
                        //用户向上滚动
                         listener.onScrollingDown();
                    }
                 }
                 prevDistanceToEnd = distanceToEnd;
            }

            if(isScrollable == null){
                //检查视图高度是否小于屏幕(即,未启用滚动)
                if((horizo​​ntalScrollBarHeight + verticalScrollExtent)> = verticalScrollRange){
                    isScrollable = Boolean.FALSE;
                }其他{
                    isScrollable = Boolean.TRUE;
                }
            }

        }

    }

    公共接口ScrollDirectionListener {

        公共无效的onScrollingUp();

        公共无效的onScrollingDown();

    }

}

这个想法是要计算distanceToEnd。如果distanceToEnd增加,则用户正在向上滚动;如果distanceToEnd增加,则用户正在向下滚动。这也将为您提供到列表末尾的确切距离。

如果您只是想知道用户是向上滚动还是向下滚动,则可以覆盖onInterceptTouchEvent来检测滚动方向,如下所示:

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event){
        开关(event.getAction()){
            案例MotionEvent.ACTION_DOWN:
                mInitialX = event.getX();
                mInitialY = event.getY();
                返回true;
            案例MotionEvent.ACTION_MOVE:
                最终浮点数x = event.getX();
                最终浮点y = event.getY();
                最终浮点yDiff = y-mInitialY; // yDiff小于0.0表示向下滚动,而yDiff大于0.0表示向上滚动。如果我尝试添加小于或大于符号,则预览拒绝显示它。
                if(yDiff小于0.0)listener.onScrollingDown();
                否则if(yDiff大于0.0)listener.onScrollingUp();
                打破;
        }
        返回super.onInterceptTouchEvent(event);
    }


1

关于检测列表视图中向上或向下滚动的技巧,只需在ListView的OnScrollListener中的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

检测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);

0

这是我首先尝试的方法:

1)使用以下方法创建一个接口(我们称之为OnScrollTopOrBottomListener):

void onScrollTop();

void onScrollBottom();

2)在列表的适配器中,添加一个成员实例,键入您创建的接口并提供setter和getter。

3)在适配器的getView()实现中,检查position参数是否为0或getCount()-1。还要检查OnScrollTopOrBottomListener实例是否为null。

4)如果位置为0,则调用onScrollTopOrBottomListener.onScrollTop()。如果position为getCount()-1,则调用onScrollTopOrBottomListener.onScrollBottom()。

5)在您的OnScrollTopOrBottomListener实现中,调用适当的方法以获取所需的数据。

希望以某种方式有所帮助。

-布兰登


0

我在使用一些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

在android GridView中的向上/向下滚动事件上加载更多项目的简单方法

    grid.setOnScrollListener(new AbsListView.OnScrollListener() {
                private int mLastFirstVisibleItem;
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    // TODO Auto-generated method stub
                    Log.d("state",String.valueOf(scrollState));


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


                    if (view.getId() == grid.getId()) {

                        final int currentFirstVisibleItem = grid.getLastVisiblePosition();
                        mLastFirstVisibleItem = grid.getFirstVisiblePosition();

                        if (currentFirstVisibleItem > mLastFirstVisibleItem) {
                            mIsScrollingUp = false;
                            if(!next.contains("null")){

                           //Call api to get products from server

                             }


                            Log.i("a", "scrolling down...");
                        } else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
                            mIsScrollingUp = true;
                            Log.i("a", "scrolling up...");
                        }

                        mLastFirstVisibleItem = currentFirstVisibleItem;
                    }

                }
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                Log.d("on scroll","");
            }
        });
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.