【问题标题】:How to find out if ListView has scrolled to top Most position?如何找出 ListView 是否已滚动到最顶部位置?
【发布时间】:2011-11-11 05:08:30
【问题描述】:

我有一个 ListView,首先它向下滚动,现在当我们向上滚动时,它到达最高点。我想检测到。有什么办法吗?我正在使用 api 级别 8 开发应用程序。请帮助..

【问题讨论】:

    标签: android


    【解决方案1】:

    编辑

    请参阅下面的 cmets 了解原因,尤其是在不同的 API 版本(尤其是更高版本)上,这不是查看列表是否位于顶部(填充等)的万无一失的方法。但是,它确实为您在 API 14 以下的设备上提供了一个解决方案:

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

    就我几年前的实施而言 - 这在当时非常有效。

    【讨论】:

    • 这并不总是在我的列表顶部时返回 0
    • (如果需要检查顶部项目是否可见,可以添加 ...getTop() > 0 || ...getTop()
    • 这对我来说真的不起作用,即使列表不在顶部,滚动它也会为 0 索引子项的 getTop 随机返回 0
    • 它将返回我认为的第一个可见孩子的顶部。
    • 很抱歉,这个解决方案并不正确,因为它没有考虑第一个元素可能具有的最终填充。
    【解决方案2】:

    我知道这个问题很老,但它显示在 Google 搜索结果的顶部。 API 级别 14 中引入了一种新方法,它提供了我们所需要的:

    http://developer.android.com/reference/android/view/View.html#canScrollVertically%28int%29

    对于旧平台,可以在 v4 支持库中使用类似的静态方法 ViewCompat 请参阅下面的编辑。

    与 Graeme 的方法不同,此方法不会因ListView 的内部视图重用和/或标头偏移引起的问题。

    编辑:最终解决方案

    我在SwipeRefreshLayout 的源代码中找到了一个方法来处理这个问题。可以改写为:

    public boolean canScrollUp(View view) {
      if (android.os.Build.VERSION.SDK_INT < 14) {
        if (view instanceof AbsListView) {
          final AbsListView absListView = (AbsListView) view;
          return absListView.getChildCount() > 0
              && (absListView.getFirstVisiblePosition() > 0 || absListView
                  .getChildAt(0).getTop() < absListView.getPaddingTop());
        } else {
          return view.getScrollY() > 0;
        }
      } else {
        return ViewCompat.canScrollVertically(view, -1);
      }
    }
    

    如果传入的视图是自定义视图,您可能需要添加自定义逻辑。

    【讨论】:

    • 请注意,canScrollVertically 和 canScrollHorizo​​ntally 的 ViewCompat 方法在 ICS 以下的平台级别上始终返回 false。除非被覆盖,否则实现将这些方法设置为返回 false,并且只有 ICS 的 impl 会覆盖这些方法。
    • @lillicoder 你是对的。我们不能在旧平台上使用这些实现。我已经编辑了答案,使其适用于所有平台。
    【解决方案3】:

    朋友们,将 Graeme 的答案与 onScroll 方法相结合...

    listView.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if(firstVisibleItem == 0 && listIsAtTop()){
                swipeRefreshLayout.setEnabled(true);
            }else{
                swipeRefreshLayout.setEnabled(false);
            }
        }
    });
    
    
    private boolean listIsAtTop()   {
        if(listView.getChildCount() == 0) return true;
        return listView.getChildAt(0).getTop() == 0;
    }
    

    【讨论】:

    • 为提到 swipeRefreshLayout 点赞。特别是我需要的。
    【解决方案4】:

    您需要检查第一个可见位置是什么,然后应用 Graeme 的解决方案来查看第一个可见列表视图项是否位于顶部位置。

    类似的东西 lv.getFirstVisiblePosition() == 0 && (lv.getChildCount() == 0 || lv.getChildAt(0).getTop() == 0)

    【讨论】:

      【解决方案5】:

      您可以使用OnScrollListener 来通知位置 0 现在可见。使用onScroll方法。

      【讨论】:

      • 我的列表项目真的很大,所以我无法比较 firstVisibleItem 是否为 0,因为该项目覆盖了一半的屏幕。如果该项目只有一半可见(在顶部)。那么firstVisibleItem也是0,不是listView的最顶层。
      • 提问者想知道最顶端的点,而不是到达顶端的项目。如果在第一个项目上但不是在最高点,这仍然会触发
      【解决方案6】:

      这个问题很老,但我有一个完美的解决方案,它可能适用于寻找解决方案的人。

      int limitRowsBDshow = 10; //size limit your list
      listViewMessages.setOnScrollListener(new AbsListView.OnScrollListener() {
              int counter = 1;
              int currentScrollState;
              int currentFirstVisibleItem;
              int currentVisibleItemCount;
              int currentTotalItemCount;
      
      
              @Override
              public void onScrollStateChanged(AbsListView view, int scrollState) {
                  this.currentScrollState = scrollState;
                  this.isScrollCompleted();
              }
      
              @Override
              public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      
                  this.currentFirstVisibleItem = firstVisibleItem;
                  this.currentVisibleItemCount = visibleItemCount;
                  this.currentTotalItemCount = totalItemCount;
              }
      
              private void isScrollCompleted() {
                  if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) {
                      /*** detect if there's been a scroll which has completed ***/
      
                      counter++;
                      if (currentFirstVisibleItem == 0 && currentTotalItemCount > limitRowsBDshow - 1) {
                           linearLay20msgMas.setVisibility(View.VISIBLE);
                      }
                  }
              }
          });
      

      这段代码是很久以前找到的(这里是 StackOverflow)。但是我找不到这个要提

      【讨论】:

        【解决方案7】:

        Graeme 的答案很接近,但缺少 user2036198 添加的内容,即对 getFirstVisiblePosition() 的检查。 getChildAt(0) 不会返回列表中第一个项目的第一个视图。 AbsListView 实现不会为每个位置创建一个视图并将它们全部保存在内存中。相反,视图回收生效以限制任何一次实例化的视图数量。

        修复很简单:

        public boolean canScrollVertically(AbsListView view) {
            boolean canScroll = false;
        
            if (view != null && view.getChildCount() > 0) {
                // First item can be partially visible, top must be 0 for the item
                canScroll = view.getFirstVisiblePosition() != 0 || view.getChildAt(0).getTop() != 0;
            }
        
            return canScroll;
        }
        

        为了在 ICS 或更高版本上获得最佳效果,请始终使用 v4 支持库中的 ViewCompat 或 View.canScrollVertically()。在较低的 API 级别上使用上述方法,因为 ViewCompat 总是为 ICS 下的 canScrollVertically() 和 canScrollHorizo​​ntally() 返回 false。

        【讨论】:

          【解决方案8】:

          如果你可以直接扩展 ListView,那么你可以在覆盖方法“onScrollChanged()”中使用名为“computeVerticalScrollOffset()”的受保护方法。

          使用受保护的方法返回 0,意味着您的 ListView 现在已到达顶部。

          代码片段

                  listView = new ListView(this){
                  @Override
                  protected void onScrollChanged(int l, int t, int oldl, int oldt) {
                      super.onScrollChanged(l, t, oldl, oldt);
          
                      if( computeVerticalScrollOffset() == 0 ){
                          // Reach top
                      }
                  }
          

          【讨论】:

            【解决方案9】:

            为时已晚,但试试这个,它在 RecyclerView 中运行良好。 -1 检查是否可以滚动到顶部,而 1 是检查是否可以滚动到底部

            if (listView.canScrollVertically(-1))
               listView.smoothScrollToPosition(0);
            else
               onBackPressed();
            

            【讨论】:

              【解决方案10】:
              lstView.setOnScrollListener(new AbsListView.OnScrollListener() {
              
                          @Override
                          public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                              //To change body of implemented methods use File | Settings | File Templates.
                              if (0 == firstVisibleItem){
                                  Toast.makeText(MyActivity.this, "Scroll to Top ", Toast.LENGTH_SHORT).show();
                              }
                          }
                      });
              

              【讨论】:

              • 提问者想知道最顶端的点,而不是到达顶端的项目。如果在第一项但不是在最高点,这仍然会触发。
              猜你喜欢
              • 1970-01-01
              • 2011-07-04
              • 2018-03-04
              • 2011-02-22
              • 1970-01-01
              • 1970-01-01
              • 2012-06-26
              • 2015-08-29
              • 1970-01-01
              相关资源
              最近更新 更多