How to check if a my ListView has scrollable number of items?
Asked Answered
B

8

18

How do you know if your ListView has enough number of items so that it can scroll?

For instance, If I have 5 items on my ListView all of it will be displayed on a single screen. But if I have 7 or more, my ListView begins to scroll. How do I know if my List can scroll programmatically?

Brahui answered 23/6, 2012 at 22:9 Comment(8)
Why do you need to know this? After all, the answer may change on orientation changes, and the answer may change based upon what is in your rows (different row layouts, wrap_content height changes based upon prose). What are you attempting to achieve?Rafaelof
5 items may not scroll on hdpi 800x480, but may scroll on ldpi 240x320, let android take care of the scrolling for you! In fact, CommonsWare's thought, that went through my mind I meant, - Why would you want to do this?Measurable
@CommonsWare, absolutely I understand that. I want to show a footer at the bottom of the activity. If the ListView scrolls I want to place the footer image as the ListView's footer view. Else I can set the visibility of another footer placed at the end of the activity's layout.Brahui
@t0mm13b, yes I am having issues with different screen sizes that is why I want to know. Also the number of items in the list could vary and I need to show a footer view depending upon the scroll.Brahui
I've tried using getMeasuredHeight() but it always returns 0. Is that because the MeasureSpec is Unspecified? There has to be a way to find out. Any pointers?Brahui
Are you trying to make the footer appear permanently regardless of listview and scrolling?Measurable
Yes, but if the list scrolls it should appear after the last list item. If the list doesn't scroll then it should appear at the bottom of the activity.Brahui
Why are people questioning the motivation behind this question, it's a great question! I want to know as well because if the content of the ListView is longer than the screen I want to add something (off screen) at the bottom of the list view.Voight
M
12

Diegosan's answer cannot differentiate when the last item is partially visible on the screen. Here is a solution to that problem.

First, the ListView must be rendered on the screen before we can check if its content is scrollable. This can be done with a ViewTreeObserver:

ViewTreeObserver observer = listView.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            if (willMyListScroll()) {
                 // Do something
            } 
        }
    });

And here is willMyListScroll():

boolean willMyListScroll() {   
    int pos = listView.getLastVisiblePosition();
    if (listView.getChildAt(pos).getBottom() > listView.getHeight()) {
        return true;
    } else {
        return false;
    }
}
Mindy answered 12/3, 2014 at 21:4 Comment(3)
Excellent solution - a null check needs to be added to the willMyListScroll() method for the getChildAt(pos). If the list is empty, it will crash :DAlexine
I believe this is wrong. getChildAt() only counts the children that are visible on screen. Meanwhile, getLastVisiblePosition returns the index based on the Adapter. So if the lastVisiblePosition is 8 because it's the 9th item in the list and there are only 4 visible items on screen, you're gonna get a crash. Verify it by calling getChildCount() and see. The indices for getChildAt are not the same as the indices for the data set. Check this out: #6767125Miniaturize
Crashing in listView.getChildAt(pos).getBottom()Chiseler
M
3

As per my comment on Mike Ortiz' answer, I believe his answer is wrong:

getChildAt() only counts the children that are visible on screen. Meanwhile, getLastVisiblePosition returns the index based on the Adapter. So if the lastVisiblePosition is 8 because it's the 9th item in the list and there are only 4 visible items on screen, you're gonna get a crash. Verify it by calling getChildCount() and see. The indices for getChildAt are not the same as the indices for the data set. Check this out: ListView getChildAt returning null for visible children

Here's my solution:

public boolean isScrollable() {
        int last = listView.getChildCount()-1; //last visible listitem view
        if (listView.getChildAt(last).getBottom()>listView.getHeight() || listView.getChildAt(0).getTop()<0) { //either the first visible list item is cutoff or the last is cutoff
                return true;
        }
        else{
            if (listView.getChildCount()==listView.getCount()) { //all visible listitem views are all the items there are (nowhere to scroll)
                return false;
            }
            else{ //no listitem views are cut off but there are other listitem views to scroll to
                return true;
            }
        }
    }
Miniaturize answered 3/2, 2015 at 4:47 Comment(1)
This solution will also work even after you've scrolled to a point on the list or rotated the phone. It's not restricted to a call right after the initial loading of the listMiniaturize
P
1

You cannot detect this before android render the screen with the listView. However, you can absolutely detect this post-render.

boolean willMyListScroll() {        
   if(listView.getLastVisiblePosition() + 1 == listView.getCount()) {
      return false;
   }

   return true;             
}

What this does is check if the listView visible window contains ALL your list view items. If it can, then the listView will never scroll and the getLastVisiblePosition() will always be equal to the total number of items in the list's dataAdapter.

Perambulate answered 24/1, 2013 at 8:23 Comment(3)
Hi, thank you. But if the last item is half visible on the screen then the list view would scroll as well.Brahui
Would removing the "+1" part of Diegosan's answer work?Trembles
No, this will not make his answer work. Check my answer below.Mindy
F
1

This is the code I wrote for showing a picture after the last row of the listview:

public class ShowTheEndListview
{
    private ImageView the_end_view;
    private TabbedFragRootLayout main_layout;
    private ListView listView;
    private float pas;
    private float the_end_img_height;
    private int has_scroll = -1;

    public ShowTheEndListview(float height)
    {
        the_end_img_height = height;
        pas = 100 / the_end_img_height;
    }

    public void setData(ImageView the_end_view, TabbedFragRootLayout main_layout, ListView listView)
    {
        this.the_end_view = the_end_view;
        this.main_layout = main_layout;
        this.listView = listView;
    }

    public void onScroll(int totalItemCount)
    {
        if(totalItemCount - 1 == listView.getLastVisiblePosition())
        {
            int pos = totalItemCount - listView.getFirstVisiblePosition() - 1;
            View last_item = listView.getChildAt(pos);

            if (last_item != null)
            {
                if(listHasScroll(last_item))
                {
//                        Log.e(TAG, "listHasScroll TRUE");
                }
                else
                {
//                        Log.e(TAG, "listHasScroll FALSE");
                }
            }
        }
    }

    private boolean listHasScroll(View last_item)
    {
        if(-1 == has_scroll)
        {
            has_scroll = last_item.getBottom() > (main_layout.getBottom() - the_end_img_height - 5) ? 1 : 0;
        }

        return has_scroll == 1;
    }

    public void resetHasScroll()
    {
        has_scroll = -1;
    }
}
Fantastic answered 6/7, 2015 at 16:18 Comment(0)
M
1

AbsListView includes this:

/**
 * Check if the items in the list can be scrolled in a certain direction.
 *
 * @param direction Negative to check scrolling up, positive to check scrolling down.
 * @return true if the list can be scrolled in the specified direction, false otherwise.
 * @see #scrollListBy(int)
 */
public boolean canScrollList(int direction);

You need to override layoutChildren() and use it within that:

@Override
protected void layoutChildren() {
    super.layoutChildren();
    isAtBottom = !canScrollList(1);
    isAtTop = !canScrollList(-1);
}
Michelmichelangelo answered 25/8, 2016 at 18:8 Comment(0)
B
0

This is how i used to check

if (listView.getAdapter() != null
                    && listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1
                    && listView.getChildAt(listView.getChildCount() - 1).getBottom() == listView.getBottom())

if it gives true, then list is at the bottom

Butane answered 16/7, 2014 at 8:24 Comment(0)
M
-1

Use the setOnScrollListener, by applying the callback to OnScrollListener, you can determine if scrolling is taking place using the pre-defined constants and handle the situation accordingly.

Measurable answered 23/6, 2012 at 22:58 Comment(1)
I would receive a callback only if the event happens, isn't it? But the layout has to be changed even before the user attempts to scroll the list.Brahui
A
-2
 boolean listBiggerThanWindow = appHeight - 50 <= mListView.getHeight();

            Toast.makeText(HomeActivity.this, "list view bigger that window? " + listBiggerThanWindow, Toast.LENGTH_LONG)
                    .show();

            if (listBiggerThanWindow) {
                // do your thing here...
               }

you can get dimensions in onCreate() by calling post(Runnable) on View.

Aposematic answered 24/3, 2015 at 15:49 Comment(1)
you use appHeight - 50. What is appHeight , what is its measure (px,dp,dip.. etc ?). Please add more information.Institute

© 2022 - 2024 — McMap. All rights reserved.