ShineDown
ShineDown

Reputation: 1879

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. I want to detect that .Is there any way?I am developing application with api level 8.Pls help..

Upvotes: 29

Views: 21977

Answers (10)

Mihae Kheel
Mihae Kheel

Reputation: 2651

Too late but try this one it works well in RecyclerView. -1 to check if it can scroll to top while 1 is to check if it can scroll to bottom

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

Upvotes: 0

Tim Nuwin
Tim Nuwin

Reputation: 2887

My friends, combining Graeme's answer with the onScroll method...

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

Upvotes: 13

Emmanuelguther
Emmanuelguther

Reputation: 1059

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). But I can not find this to mention

Upvotes: 1

Graeme
Graeme

Reputation: 25864

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). However, it does give you a start for a solution on devices below 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.

Upvotes: 41

KunYu Tsai
KunYu Tsai

Reputation: 682

If you can extends ListView directly, then you can use the protected method called "computeVerticalScrollOffset()" inside the override method "onScrollChanged()".

With that protected method return 0, means that your ListView is now reached at top.

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

Upvotes: 0

topduo
topduo

Reputation: 508

I know this question is old, but it shows up top in Google search results. There is a new method introduced in API level 14 that gives exactly what we needed:

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. 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.

Edit: final solution

I've found a method in the source code of SwipeRefreshLayout that handles this. 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.

Upvotes: 21

lillicoder
lillicoder

Reputation: 552

Graeme's answer is close but is missing something that user2036198 added, a check for getFirstVisiblePosition(). getChildAt(0) doesn't return the very first view for the very first item in the list. AbsListView implementations don't make a single view for every position and keep them all in memory. 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(). Use the above method on lower API levels as ViewCompat always returns false for canScrollVertically() and canScrollHorizontally() below ICS.

Upvotes: 0

user2036198
user2036198

Reputation: 21

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.

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

Upvotes: 2

Leonly91
Leonly91

Reputation: 613

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

Upvotes: -1

Cyril Mottier
Cyril Mottier

Reputation: 1624

You can use an OnScrollListener to be notified the position 0 is now visible. Use the onScrollmethod.

Upvotes: 1

Related Questions