Voir si ListView est en bas?

puis-je savoir si mon ListView est en bas? Je veux dire par là que le dernier objet est entièrement visible.

99
demandé sur fhucho 2011-02-26 02:05:07

22 réponses

Édité :

depuis que j'ai étudié dans ce domaine particulier dans une de mes applications, je peux écrire une réponse prolongée pour les futurs lecteurs de cette question.

mettre en œuvre un OnScrollListener , définir votre ListView 's onScrollListener et alors vous devriez être en mesure de gérer les choses correctement.

par exemple:

private int preLast;
// Initialization stuff.
yourListView.setOnScrollListener(this);

// ... ... ...

@Override
public void onScroll(AbsListView lw, final int firstVisibleItem,
        final int visibleItemCount, final int totalItemCount)
{

    switch(lw.getId()) 
    {
        case R.id.your_list_id:     

            // Make your calculation stuff here. You have all your
            // needed info from the parameters of this function.

            // Sample calculation to determine if the last 
            // item is fully visible.
            final int lastItem = firstVisibleItem + visibleItemCount;

            if(lastItem == totalItemCount)
            {
                if(preLast!=lastItem)
                {
                    //to avoid multiple calls for last item
                    Log.d("Last", "Last");
                    preLast = lastItem;
                }
            }
    }
}
163
répondu Wroclai 2016-08-30 14:01:40

réponse tardive, mais si vous souhaitez simplement vérifier si votre ListView est scrolled tout le chemin vers le bas ou non, sans créer un écouteur d'événement, vous pouvez utiliser ce if-statement:

if (yourListView.getLastVisiblePosition() == yourListView.getAdapter().getCount() -1 &&
    yourListView.getChildAt(yourListView.getChildCount() - 1).getBottom() <= yourListView.getHeight())
{
    //It is scrolled all the way down here

}

d'Abord, il vérifie si la dernière position est en vue. Ensuite, il vérifie si le bas du dernier bouton s'aligne avec le bas de ListView. Vous pouvez faire quelque chose de similaire pour savoir si c'est tout le chemin au sommet:

if (yourListView.getFirstVisiblePosition() == 0 &&
    yourListView.getChildAt(0).getTop() >= 0)
{
    //It is scrolled all the way up here

}
68
répondu Martijn 2013-10-06 00:43:07

je L'ai fait:

listView.setOnScrollListener(new AbsListView.OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE 
            && (listView.getLastVisiblePosition() - listView.getHeaderViewsCount() -
            listView.getFooterViewsCount()) >= (adapter.getCount() - 1)) {

        // Now your listview has hit the bottom
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }
});
14
répondu t-gao 2016-11-22 05:45:00

quelque Chose à l'effet de:

if (getListView().getLastVisiblePosition() == (adapter.items.size() - 1))
10
répondu Chris Stewart 2011-04-23 15:59:26
public void onScrollStateChanged(AbsListView view, int scrollState)        
{
    if (!view.canScrollList(View.SCROLL_AXIS_VERTICAL) && scrollState == SCROLL_STATE_IDLE)    
    {
        //When List reaches bottom and the list isn't moving (is idle)
    }
}

ça a marché pour moi.

5
répondu Janwilx72 2016-07-31 13:02:01

cela peut être

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // TODO Auto-generated method stub

                if (scrollState == 2)
                    flag = true;
                Log.i("Scroll State", "" + scrollState);
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) {
                // TODO Auto-generated method stub
                if ((visibleItemCount == (totalItemCount - firstVisibleItem))
                        && flag) {
                    flag = false;



                    Log.i("Scroll", "Ended");
                }
            }
4
répondu lazy lord 2014-08-20 12:21:41

il était assez douloureux de traiter le défilement, détecter quand il est terminé et il est en effet au bas de la liste (Pas bas de l'écran visible), et déclenche mon service une seule fois, pour récupérer des données à partir du web. Cependant, il fonctionne très bien maintenant. Le code est le suivant pour le bénéfice de quiconque fait face à la même situation.

NOTE: j'ai dû déplacer mon code lié à l'adaptateur dans onViewCreated au lieu de onCreate et de detect scrolling principalement comme ceci:

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (getListView().getLastVisiblePosition() == (adapter.getCount() - 1))
        if (RideListSimpleCursorAdapter.REACHED_THE_END) {
            Log.v(TAG, "Loading more data");
            RideListSimpleCursorAdapter.REACHED_THE_END = false;
            Intent intent = new Intent(getActivity().getApplicationContext(), FindRideService.class);
            getActivity().getApplicationContext().startService(intent);
        }
}

Ici RideListSimpleCursorAdapter.REACHED_THE_END est une variable supplémentaire dans mon SimpleCustomAdapter qui est définie comme ceci:

if (position == getCount() - 1) {
      REACHED_THE_END = true;
    } else {
      REACHED_THE_END = false;
    }

seulement lorsque ces deux conditions sont remplies, cela signifie que je suis effectivement en bas de la liste, et que mon service ne fonctionnera qu'une seule fois. Si je n'attrape pas le REACHED_THE_END, même défiler à l'envers déclenche le service à nouveau, aussi longtemps que le dernier élément est en vue.

3
répondu zeeshan 2013-07-13 19:27:58

canScrollVertically(int direction) fonctionne pour tous les points de vue, et semble faire ce que vous avez demandé, avec moins de code que la plupart des autres réponses. Branchez un nombre positif, et si le résultat est faux, vous êtes au fond.

c'est à dire:

if (!yourView.canScrollVertically(1)) { //you've reached bottom }

3
répondu Joel H 2015-09-18 12:43:50

pour développer un peu l'une des réponses ci-dessus, c'est ce que j'ai dû faire pour la faire fonctionner complètement. Il semble y avoir environ 6dp de rembourrage intégré à l'intérieur des ListViews, et onScroll() était appelé quand la liste était vide. Cette traite à la fois de ces choses. Il pourrait probablement être optimisé un peu, mais est écrit plus pour la clarté.

Side note: j'ai essayé plusieurs techniques de conversion dp à pixel différentes, et celle-ci dp2px() a été la meilleur.

myListView.setOnScrollListener(new OnScrollListener() {
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (visibleItemCount > 0) {
            boolean atStart = true;
            boolean atEnd = true;

            View firstView = view.getChildAt(0);
            if ((firstVisibleItem > 0) ||
                    ((firstVisibleItem == 0) && (firstView.getTop() < (dp2px(6) - 1)))) {
                // not at start
                atStart = false;
            }

            int lastVisibleItem = firstVisibleItem + visibleItemCount;
            View lastView = view.getChildAt(visibleItemCount - 1);
            if ((lastVisibleItem < totalItemCount) ||
                    ((lastVisibleItem == totalItemCount) &&
                            ((view.getHeight() - (dp2px(6) - 1)) < lastView.getBottom()))
                    ) {
                        // not at end
                    atEnd = false;
                }

            // now use atStart and atEnd to do whatever you need to do
            // ...
        }
    }
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }
});

private int dp2px(int dp) {
    return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
2
répondu CSX321 2013-08-23 21:15:47

Je ne peux pas encore commenter parce que je n'ai pas assez de réputation, mais dans la réponse de @Ali Imran et @Wroclai je pense que quelque chose manque. Avec ce morceau de code, une fois que vous mettez à jour preLast, il n'exécutera plus jamais le Log. Dans mon problème spécifique, je veux exécuter une opération à chaque fois que je fais défiler vers le bas, mais une fois que preLast est mis à jour vers LastItem, cette opération n'est plus jamais exécutée.

private int preLast;
// Initialization stuff.
yourListView.setOnScrollListener(this);

// ... ... ...

@Override
public void onScroll(AbsListView lw, final int firstVisibleItem,
                 final int visibleItemCount, final int totalItemCount) {

switch(lw.getId()) {
    case android.R.id.list:     

        // Make your calculation stuff here. You have all your
        // needed info from the parameters of this function.

        // Sample calculation to determine if the last 
        // item is fully visible.
         final int lastItem = firstVisibleItem + visibleItemCount;
       if(lastItem == totalItemCount) {
          if(preLast!=lastItem){ //to avoid multiple calls for last item
            Log.d("Last", "Last");
            preLast = lastItem;
          }
       } else {
            preLast = lastItem;
}

}

Avec qui "else" vous êtes maintenant en mesure d'exécuter votre code (Log, dans ce cas) à chaque fois que vous faites défiler vers le bas une fois de plus.

2
répondu Teno Gonzalez Dos Santos 2015-03-26 11:32:54

pour que votre liste appelle quand la liste atteint la dernière et si une erreur se produit, alors cela n'appellera plus l'endoflistview . Ce code aidera aussi ce scénario.

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
    final int lastPosition = firstVisibleItem + visibleItemCount;
    if (lastPosition == totalItemCount) {
        if (previousLastPosition != lastPosition) { 

            //APPLY YOUR LOGIC HERE
        }
        previousLastPosition = lastPosition;
    }
    else if(lastPosition < previousLastPosition - LIST_UP_THRESHOLD_VALUE){
        resetLastIndex();
    }
}

public void resetLastIndex(){
    previousLastPosition = 0;
}

où la valeur LIST_UP_THRESHOLD_VALUE peut être n'importe quelle valeur entière(j'ai utilisé 5) où votre liste est scrollée vers le haut et tout en retournant à la fin, cela appellera la fin de la vue de liste de nouveau.

1
répondu Vyshnavi 2014-08-06 05:52:22

j'ai trouvé une façon très agréable de charger automatiquement la page suivante d'une manière qui ne nécessite pas votre propre ScrollView (comme la réponse acceptée exige).

sur ParseQueryAdapter il y a une méthode appelée getNextPageView qui est là pour vous permettre de fournir votre propre vue personnalisée qui apparaît à la fin de la liste quand il y a plus de données à charger donc il ne se déclenche que lorsque vous avez atteint la fin de vous le jeu de page actuel (c'est le " load more.."vue par défaut). Cette méthode est seulement appelé quand il ya plus de données à charger donc c'est un excellent endroit pour appeler loadNextPage(); de cette façon l'adaptateur fait tout le travail difficile pour vous dans la détermination quand de nouvelles données doivent être chargées et il ne sera pas appelé du tout si vous avez atteint la fin de l'ensemble de données.

public class YourAdapter extends ParseQueryAdapter<ParseObject> {

..

@Override
public View getNextPageView(View v, ViewGroup parent) {
   loadNextPage();
   return super.getNextPageView(v, parent);
  }

}

alors à l'intérieur de votre activité / fragment vous avez juste à régler l'adaptateur et les nouvelles données seront automatiquement mis à jour pour vous comme magie.

adapter = new YourAdapter(getActivity().getApplicationContext());
adapter.setObjectsPerPage(15);
adapter.setPaginationEnabled(true);
yourList.setAdapter(adapter);
1
répondu Max Worg 2015-03-07 19:43:55

pour détecter si le dernier article est entièrement visible , vous pouvez simplement ajouter le calcul sur le fond du dernier article visible de la vue par lastItem.getBottom() .

yourListView.setOnScrollListener(this);   

@Override
public void onScroll(AbsListView view, final int firstVisibleItem,
                 final int visibleItemCount, final int totalItemCount) {

    int vH = view.getHeight();
    int topPos = view.getChildAt(0).getTop();
    int bottomPos = view.getChildAt(visibleItemCount - 1).getBottom();

    switch(view.getId()) {
        case R.id.your_list_view_id:
            if(firstVisibleItem == 0 && topPos == 0) {
                //TODO things to do when the list view scroll to the top
            }

            if(firstVisibleItem + visibleItemCount == totalItemCount 
                && vH >= bottomPos) {
                //TODO things to do when the list view scroll to the bottom
            }
            break;
    }
}
1
répondu Will 2015-03-15 07:31:22

je suis allé avec:

@Override
public void onScroll(AbsListView listView, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
    if(totalItemCount - 1 == favoriteContactsListView.getLastVisiblePosition())
    {
        int pos = totalItemCount - favoriteContactsListView.getFirstVisiblePosition() - 1;
        View last_item = favoriteContactsListView.getChildAt(pos);

        //do stuff
    }
}
1
répondu Goran Horia Mihail 2015-07-06 12:16:45

dans la méthode getView() (d'une classe dérivée de BaseAdapter ) on peut vérifier si la position de la vue courante est égale à la liste des éléments dans la Adapter . Si c'est le cas, alors cela signifie que nous avons atteint la fin/bas de la liste:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // ...

    // detect if the adapter (of the ListView/GridView) has reached the end
    if (position == getCount() - 1) {
        // ... end of list reached
    }
}
1
répondu ramon 2015-11-20 21:30:53

je trouve un meilleur moyen de détecter listview scroll end the bottom, d'abord détecter scoll end par ce

implémentation de onscrollistener pour détecter la fin de la défilement dans un ListView

 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    this.currentFirstVisibleItem = firstVisibleItem;
    this.currentVisibleItemCount = visibleItemCount;
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    this.currentScrollState = scrollState;
    this.isScrollCompleted();
 }

private void isScrollCompleted() {
    if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) {
        /*** In this way I detect if there's been a scroll which has completed ***/
        /*** do the work! ***/
    }
}

finalement combiner la réponse de Martijn

OnScrollListener onScrollListener_listview = new OnScrollListener() {       

        private int currentScrollState;
        private int currentVisibleItemCount;

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            // TODO Auto-generated method stub

            this.currentScrollState = scrollState;
            this.isScrollCompleted();
        }

        @Override
        public void onScroll(AbsListView lw, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            // TODO Auto-generated method stub
            this.currentVisibleItemCount = visibleItemCount;

        }

        private void isScrollCompleted() {
            if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) {
                /*** In this way I detect if there's been a scroll which has completed ***/
                /*** do the work! ***/

                if (listview.getLastVisiblePosition() == listview.getAdapter().getCount() - 1
                        && listview.getChildAt(listview.getChildCount() - 1).getBottom() <= listview.getHeight()) {
                    // It is scrolled all the way down here
                    Log.d("henrytest", "hit bottom");
                }


            }
        }

    };
0
répondu HenryChuang 2017-05-23 12:18:14

grand merci aux affiches dans stackoverflow! J'ai combiné quelques idées et créé l'auditeur de classe pour les activités et les fragments (de sorte que ce code est plus réutilisable rendant le code plus rapide à écrire et beaucoup plus propre).

Tout ce que vous avez à faire quand vous avez ma classe est d'implémenter l'interface (et bien sûr de créer la méthode pour elle) qui est déclarée dans ma classe et de créer l'objet de cette classe passant des arguments.

/**
* Listener for getting call when ListView gets scrolled to bottom
*/
public class ListViewScrolledToBottomListener implements AbsListView.OnScrollListener {

ListViewScrolledToBottomCallback scrolledToBottomCallback;

private int currentFirstVisibleItem;
private int currentVisibleItemCount;
private int totalItemCount;
private int currentScrollState;

public interface ListViewScrolledToBottomCallback {
    public void onScrolledToBottom();
}

public ListViewScrolledToBottomListener(Fragment fragment, ListView listView) {
    try {
        scrolledToBottomCallback = (ListViewScrolledToBottomCallback) fragment;
        listView.setOnScrollListener(this);
    } catch (ClassCastException e) {
        throw new ClassCastException(fragment.toString()
                + " must implement ListViewScrolledToBottomCallback");
    }
}

public ListViewScrolledToBottomListener(Activity activity, ListView listView) {
    try {
        scrolledToBottomCallback = (ListViewScrolledToBottomCallback) activity;
        listView.setOnScrollListener(this);
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement ListViewScrolledToBottomCallback");
    }
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    this.currentFirstVisibleItem = firstVisibleItem;
    this.currentVisibleItemCount = visibleItemCount;
    this.totalItemCount = totalItemCount;
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    this.currentScrollState = scrollState;
    if (isScrollCompleted()) {
        if (isScrolledToBottom()) {
            scrolledToBottomCallback.onScrolledToBottom();
        }
    }
}

private boolean isScrollCompleted() {
    if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) {
        return true;
    } else {
        return false;
    }
}

private boolean isScrolledToBottom() {
    System.out.println("First:" + currentFirstVisibleItem);
    System.out.println("Current count:" + currentVisibleItemCount);
    System.out.println("Total count:" + totalItemCount);
    int lastItem = currentFirstVisibleItem + currentVisibleItemCount;
    if (lastItem == totalItemCount) {
        return true;
    } else {
        return false;
    }
}
}
0
répondu Janusz Hain 2016-06-23 15:47:56

vous devez ajouter une ressource de pied de page xml vide à votre listView et détecter si ce pied de page est visible.

    private View listViewFooter;
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_newsfeed, container, false);

        listView = (CardListView) rootView.findViewById(R.id.newsfeed_list);
        footer = inflater.inflate(R.layout.newsfeed_listview_footer, null);
        listView.addFooterView(footer);

        return rootView;
    }

alors dans votre listeneur listView scroll vous faites ceci

@
Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  if (firstVisibleItem == 0) {
    mSwipyRefreshLayout.setDirection(SwipyRefreshLayoutDirection.TOP);
    mSwipyRefreshLayout.setEnabled(true);
  } else if (firstVisibleItem + visibleItemCount == totalItemCount) //If last row is visible. In this case, the last row is the footer.
  {
    if (footer != null) //footer is a variable referencing the footer view of the ListView. You need to initialize this onCreate
    {
      if (listView.getHeight() == footer.getBottom()) { //Check if the whole footer is visible.
        mSwipyRefreshLayout.setDirection(SwipyRefreshLayoutDirection.BOTTOM);
        mSwipyRefreshLayout.setEnabled(true);
      }
    }
  } else
    mSwipyRefreshLayout.setEnabled(false);
}
0
répondu Joseph Mhanna 2016-07-12 16:06:56

si vous définissez une balise sur une vue du dernier élément de listview, plus tard vous pouvez récupérer la vue avec la balise, si la vue est nulle c'est parce que la vue n'est plus chargée. Comme ceci:

private class YourAdapter extends CursorAdapter {
    public void bindView(View view, Context context, Cursor cursor) {

         if (cursor.isLast()) {
            viewInYourList.setTag("last");
         }
         else{
            viewInYourList.setTag("notLast");
         }

    }
}

puis si vous avez besoin de savoir si le dernier article est chargé

View last = yourListView.findViewWithTag("last");
if (last != null) {               
   // do what you want to do
}
0
répondu Dante Carvalho Costa 2016-10-07 01:16:12

Janwilx72 est bon,mais c'est min sdk est 21,j'ai donc créer cette méthode:

private boolean canScrollList(@ScrollOrientation int direction, AbsListView listView) {
    final int childCount = listView.getChildCount();
    if (childCount == 0) {
        return false;
    }

    final int firstPos = listView.getFirstVisiblePosition();
    final int paddingBottom = listView.getListPaddingBottom();
    final int paddingTop = listView.getListPaddingTop();
    if (direction > 0) {
        final int lastBottom = listView.getChildAt(childCount - 1).getBottom();
        final int lastPos    = firstPos + childCount;
        return lastPos < listView.getChildCount() || lastBottom > listView.getHeight() - paddingBottom;
    } else {
        final int firstTop = listView.getChildAt(0).getTop();
        return firstPos > 0 || firstTop < paddingTop;
    }
}

pour la gravure:

protected static final int SCROLL_UP = -1;
protected static final int SCROLL_DOWN = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SCROLL_UP, SCROLL_DOWN})
protected @interface Scroll_Orientation{}

peut-être tard, juste pour les retardataires

0
répondu xiaoyee 2016-12-01 06:47:42
public void onScroll(AbsListView view, int firstVisibleItem,
                         int visibleItemCount, int totalItemCount) {
        int lastindex = view.getLastVisiblePosition() + 1;

        if (lastindex == totalItemCount) { //showing last row
            if ((view.getChildAt(visibleItemCount - 1)).getTop() == view.getHeight()) {
                //Last row fully visible
            }
        }
    }
0
répondu John Ruban Singh 2018-05-10 13:55:12

ceci fera défiler votre liste jusqu'à la dernière entrée.

ListView listView = new ListView(this);
listView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
listView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
listView.setStackFromBottom(true);
-5
répondu salman khalid 2012-09-17 11:42:01