简体   繁体   English

如何确定ListView是否已滚动到顶部大多数位置?

[英]How to find out if ListView has scrolled to top Most position?

I have a ListView, first its scrolled down, now when we scroll up,it reach top most point. 我有一个ListView,首先它向下滚动,现在当我们向上滚动时,它达到最高点。 I want to detect that .Is there any way?I am developing application with api level 8.Pls help.. 我想检测一下。有什么办法吗?我正在用api级别开发应用程序8.Pls帮助..

edit 编辑

See comments below as to why, especially on different API versions (esp later ones), this isn't a foolproof way to see if you're list is at the top (padding etc). 请参阅下面的评论,为什么,特别是在不同的API版本(尤其是后来的版本)上,这不是一个简单的方法,看看你的列表是否在顶部(填充等)。 However, it does give you a start for a solution on devices below API 14: 但是,它确实为您在API 14以下的设备上提供解决方案的开始:

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

As far as my implementation years ago - this worked perfectly at the time. 就我多年前的实施情况而言 - 这在当时完美无缺。

I know this question is old, but it shows up top in Google search results. 我知道这个问题很老,但它在Google搜索结果中显示出来。 There is a new method introduced in API level 14 that gives exactly what we needed: API级别14中引入了一种新方法,可以提供我们所需的内容:

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

For older platforms one can use similar static methods of ViewCompat in the v4 support library. 对于较旧的平台,可以在v4支持库中使用类似的ViewCompat静态方法。 See edit below. 见下面的编辑。

Unlike Graeme's method, this method is immune of problems caused by the internal view reuse of ListView and/or header offset. 与Graeme的方法不同,此方法不受ListView的内部视图重用和/或标头偏移引起的问题的影响。

Edit: final solution 编辑:最终解决方案

I've found a method in the source code of SwipeRefreshLayout that handles this. 我在SwipeRefreshLayout的源代码中找到了一个方法来处理这个问题。 It can be rewritten as: 它可以改写为:

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

You may need to add custom logic if the passed-in view is a custom view. 如果传入视图是自定义视图,则可能需要添加自定义逻辑。

My friends, combining Graeme 's answer with the onScroll method... 我的朋友们,将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;
}

You will need to check what is the first visible position then applying Graeme's solution to see if the first visible listview item is at the top position. 您将需要检查第一个可见位置,然后应用Graeme的解决方案,以查看第一个可见列表视图项是否位于顶部位置。

Something like lv.getFirstVisiblePosition() == 0 && (lv.getChildCount() == 0 || lv.getChildAt(0).getTop() == 0) 类似于lv.getFirstVisiblePosition()== 0 &&(lv.getChildCount()== 0 || lv.getChildAt(0).getTop()== 0)

This question is old but I have a solution that works perfectly and it is possible that works for someone looking for a solution. 这个问题很老,但我有一个完美的解决方案,它可能适用于寻找解决方案的人。

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

This code is found a time ago (here StackOverflow). 这段代码是很久以前发现的(这里是StackOverflow)。 But I can not find this to mention 但我无法提及这一点

You can use an OnScrollListener to be notified the position 0 is now visible. 您可以使用OnScrollListener通知位置0现在可见。 Use the onScroll method. 使用onScroll方法。

Graeme's answer is close but is missing something that user2036198 added, a check for getFirstVisiblePosition(). Graeme的答案很接近,但遗漏了user2036198添加的内容,检查了getFirstVisiblePosition()。 getChildAt(0) doesn't return the very first view for the very first item in the list. getChildAt(0)不返回列表中第一个项目的第一个视图。 AbsListView implementations don't make a single view for every position and keep them all in memory. AbsListView实现不会为每个位置创建单个视图,并将它们全部保存在内存中。 Instead, view recycling takes effect to limit the number of views instantiated at any one time. 相反,视图回收生效会限制任何时候实例化的视图数量。

The fix is pretty simple: 修复非常简单:

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

For best results on ICS or higher, always use ViewCompat from the v4 support library or View.canScrollVertically(). 要获得ICS或更高版本的最佳结果,请始终使用v4支持库中的ViewCompat或View.canScrollVertically()。 Use the above method on lower API levels as ViewCompat always returns false for canScrollVertically() and canScrollHorizontally() below ICS. 在较低的API级别上使用上述方法,因为ViewCompat始终为ICS下方的canScrollVertically()和canScrollHorizo​​ntally()返回false。

If you can extends ListView directly, then you can use the protected method called "computeVerticalScrollOffset()" inside the override method "onScrollChanged()". 如果可以直接扩展ListView,那么可以在override方法“onScrollChanged()”中使用名为“computeVerticalScrollOffset()”的受保护方法。

With that protected method return 0, means that your ListView is now reached at top. 使用该受保护的方法返回0,表示您的ListView现在已到达顶部。

Code Snippet 代码片段

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM