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

Posted

技术标签:

【中文标题】在 ListView 中检测向上滚动和向下滚动【英文标题】:Detect Scroll Up & Scroll down in ListView 【发布时间】:2013-05-23 08:50:18 【问题描述】:

我有以下要求:

首先,从服务器和项目中获取第 2 页的数据 填充在 ListView 中。

考虑到场景中的上一页和下一页都可用,添加如下代码:

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

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

我应该设置什么条件来检测以下方法的向上滚动和向下滚动:

    void onScroll(AbsListView 视图,int firstVisibleItem,int visibleItemCount, int totalItemCount) void onScrollStateChanged(AbsListView view, int scrollState)

在检测到动作:向上滚动和向下滚动之后,相应地,将使用 prev page no 或 next page no 调用服务,以获取要填充到 Listview 中的项目。

任何输入都会有所帮助。

浏览了以下链接,但没有返回正确的向上/向下滚动操作:

link 1 link 2

【问题讨论】:

【参考方案1】:

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

【讨论】:

如果要在 scollState 为SCROLL_STATE_IDLE 之前确定滚动方向怎么办?比如 scrollState 是 SCROLL_STATE_FLINGSCROLL_STATE_TOUCH_SCROLL 对我有用的是将这段代码添加到 OnScroll 而不是 onScrollStateChanged 如果所有项目都可见,例如您有 2 个项目并且您想像 whatsapp 一样向上滚动以加载更多项目,则将无法工作【参考方案2】:

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

添加另一个类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_
    android:layout_/>

这是我的第一个话题,不要苛责我。 =)

【讨论】:

这正是我想要的。奇迹般有效! +1! 这非常精确!!谢谢 为什么不扩展滚动监听器而不是整个视图?仅为滚动事件扩展视图并不是一个好习惯,特别是如果以后您想附加一个新的滚动侦听器...【参考方案3】:

这是一个简单的实现:

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

【讨论】:

它基本上不适用于小卷轴。这实现了“一次一个”检测器。它仅在您滚动“整个单元格”时触发。 我相信这工作得很好(记住它是单元格的,而不是像素的)。与下面的“四个测试”方法相比,我对其进行了广泛的测试(例如 Elulici 的答案)。希望它可以帮助某人。 伟大而简单的解决方案。 太棒了!完美运行! 我得到的最简单的解决方案,谢谢【参考方案4】:

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

        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 子项触摸,还是点击?【参考方案5】:
            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;
                        
                    );

【讨论】:

这确实是最好的解决方案,因为所有其他解决方案都取决于当前和最后一个可见项目。当依赖于列表项时,你也依赖于适配器,如果你滚动并且适配器没有膨胀下一个项目,你不知道用户是向上还是向下滚动。 这确实是一个糟糕的解决方案,因为您每次都在 onScrollStateChanged 设置视图触摸侦听器,这有很多开销。【参考方案6】:

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

【讨论】:

不错的答案!我只需要添加一个检查 firstCell 是否为空(因为它可能发生,它还没有膨胀)。 这是我找到的关于检测滚动方向的最佳和最简单的答案!即使物品高度小或大也正确,它工作完美且稳定。非常感谢您。顺便说一句,只是一件小事,您可以将 previousDistanceFromFirstCellToTop 变量放在内部匿名 OnScrollListener 类中以使其更好。 很好的解决方案!只缺少一件事:在View firstCell = view.getChildAt(0); 之后添加:if(firstCell == null) return; 【参考方案7】:

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

如果您有页眉或页脚,您也应该检查可见计数。如果它增加,则意味着您正在向下滚动。 (如果有页脚而不是页眉,则反转它)

如果您的列表视图中没有任何页眉或页脚,您可以删除检查可见项目数的行。

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;

【讨论】:

这仅在您移动“一个完整的单元格”后才有效。它不会检测到小的运动。它确实可靠地工作。请注意,当单元格边框通过屏幕的底部(或包围任何内容)而不是顶部时,它会触发。顺便说一句,伙计,我相信你已经上下调换了! 我看不出这个答案和更简单的方法在功能上的任何区别,例如GaiRom 上面。我广泛测试了极端情况等。 Eluleci,有额外比较的原因吗?【参考方案8】:

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

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?? ListView 中受保护的方法 感谢一百万的及时响应。我似乎无法使用它:我只是得到“找不到符号......”我尝试了所有视图。 computeVerticalScrollOffset(), myListView.computeVerticalScrollOffset() 并在您的代码中调用它。抱歉,我是 ios 的 Android 新手(我喜欢 Android!) 由于是受保护的方法,所以需要扩展ListView。【参考方案9】:

为了也检测较大元素的滚动,我更喜欢 onTouch 侦听器:

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

【讨论】:

【参考方案10】:

存储 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()。 我有一个代码,每次都会调用 onScroll!你确定你的监听器一直在运行吗?设置 mListViewActual.setOnScrollListener(this) 不考虑任何条件! 我已经无条件添加了 mListViewActual.setOnScrollListener(this)。当用户尝试向上滚动时,仍然不会调用 onScroll(),即超出在这种情况下为 0 的顶部可见项目。当前,如前所述,用户位于第 2 页。仅当用户尝试滚动时up ,即在第一个可见项目和 onScroll() 被调用之后,可以对服务器进行下一个服务调用以获取第 1 页的数据。【参考方案11】:

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

要检测您的滚动条是否在顶部,您可以使用它。

public boolean checkAtTop() 

    if(listView.getChildCount() == 0) return true;
    return listView.getChildAt(0).getTop() == 0;

这将检查您的滚动条是否位于顶部。现在,为了做到这一点,你必须将你拥有的孩子的数量传递给它,并检查这个数字。您可能必须计算一次屏幕上有多少人,然后从您的孩子人数中减去。我从来没有这样做过。希望这会有所帮助

【讨论】:

【参考方案12】:

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

公共类 ScrollTrackingListView 扩展 ListView 私人布尔readyForMeasurement = false; 私有布尔 isScrollable = null; 私人浮动 prevDistanceToEnd = -1.0; 私有 ScrollDirectionListener 监听器 = null; 公共 ScrollTrackingListView(上下文上下文) 超级(上下文); 在里面(); public Sc​​rollTrackingListView(上下文上下文,AttributeSet attrs) 超级(上下文,属性); 在里面(); public Sc​​rollTrackingListView(上下文上下文,AttributeSet attrs,int defStyle) 超级(上下文,属性,defStyle); 在里面(); 私人无效初始化() ViewTreeObserver 观察者 = getViewTreeObserver(); 观察者.addOnGlobalLayoutListener(globalLayoutListener); setOnScrollListener(scrollListener); 私有 ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = 新 ViewTreeObserver.OnGlobalLayoutListener() @覆盖 公共无效 onGlobalLayout() 准备好测量=真; 计算距离结束(); ; 公共无效 registerScrollDirectionListener(ScrollDirectionListener 监听器) scrollDirectionListener = 监听器; 公共无效 unregisterScrollDirectionListener() 滚动方向监听器 = null; 私有 OnScrollListener 滚动监听器 = 新的 OnScrollListener() @覆盖 公共无效 onScrollStateChanged(AbsListView absListView,int i) 计算距离结束(); @覆盖 公共无效 onScroll(AbsListView absListView,int i,int i1,int i2) // 没做什么 ; 私人无效计算距离结束() 如果(准备好测量) // 我正在使用布局的高度、水平滚动条和 // 内容连同向下滚动偏移量 // 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 单位的值。 * */ 浮动距离ToEnd = ((float)(verticalScrollRange - verticalScrollOffset))/((float)(verticalScrollExtent)); 如果(prevDistanceToEnd == -1) prevDistanceToEnd = distanceToEnd; 别的 如果(听众!= null) 如果(距离到结束> prevDistanceToEnd) // 用户向上滚动 listener.onScrollingUp(); 别的 // 用户向上滚动 listener.onScrollingDown(); prevDistanceToEnd = distanceToEnd; if(isScrollable == null) // 检查视图高度是否小于屏幕(即不启用滚动) if((horizo​​ntalScrollBarHeight + verticalScrollExtent) >= verticalScrollRange) isScrollable = Boolean.FALSE; 别的 isScrollable = Boolean.TRUE; 公共接口 ScrollDirectionListener 公共无效 onScrollingUp(); 公共无效 onScrollingDown();

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

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

@覆盖 公共布尔 onInterceptTouchEvent(MotionEvent 事件) 开关 (event.getAction()) 案例 MotionEvent.ACTION_DOWN: mInitialX = event.getX(); mInitialY = event.getY(); 返回真; 案例 MotionEvent.ACTION_MOVE: 最终浮点数 x = event.getX(); 最终浮动 y = event.getY(); 最终浮点 yDiff = y - mInitialY; // yDiff 小于 0.0 表示向下滚动,而 yDiff 大于 0.0 表示向上滚动。如果我尝试添加小于或大于符号,预览将拒绝显示它。 if(yDiff 小于 0.0) listener.onScrollingDown(); else if(yDiff 大于 0.0) listener.onScrollingUp(); 休息; 返回 super.onInterceptTouchEvent(event);

【讨论】:

【参考方案13】:

在listview中检测向上或向下滚动的技巧,你只需在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();
            
        
    

【讨论】:

【参考方案14】:

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

【讨论】:

【参考方案15】:

在 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","");
            
        );

【讨论】:

【参考方案16】:

这是我首先要尝试的:

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

void onScrollTop();

void onScrollBottom();

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

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

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

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

希望在某种程度上有所帮助。

-布兰登

【讨论】:

【参考方案17】:

我在使用一些 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 来检测滚动,直到您遇到该 margin 。这样可以避免在显示或隐藏视图时出现问题并避免它们闪烁。

【讨论】:

以上是关于在 ListView 中检测向上滚动和向下滚动的主要内容,如果未能解决你的问题,请参考以下文章

Listview setOnScrollListener 向上向下滚动

Android ListView 在向下滚动时显示不正确的内容,然后在向上滚动时显示正确的内容

如何检测在radlistview中是向上滚动还是向下滚动

如何检测 SwiftUI List 中的向上、向下、顶部和底部滚动

在Android中向上滚动ListView时加载页面

javascript 检测向下滚动和向上事件jQuery