Узнайте, прокручивается ли ListView до конца? - программирование
Подтвердить что ты не робот

Узнайте, прокручивается ли ListView до конца?

Могу ли я узнать, прокручивается ли ListView вниз? Под этим я подразумеваю, что последний элемент полностью виден.

4b9b3361

Ответ 1

Edited

Поскольку я изучал этот вопрос в одном из своих приложений, я могу написать расширенный ответ для будущих читателей этого вопроса.

Внесите OnScrollListener, установите ListView OnScrollListener, а затем вы сможете правильно обрабатывать вещи.

Например:

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

Ответ 2

Поздний ответ, но если вы просто хотите проверить, прокручивается ли ListView до конца или нет, без создания прослушивателя событий вы можете использовать этот оператор if:

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

}

Сначала он проверяет, отображается ли последняя возможная позиция. Затем он проверяет, совпадает ли нижняя часть последней кнопки с нижней частью ListView. Вы можете сделать что-то похожее, чтобы узнать, все ли это вверху:

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

}

Ответ 3

Что-то вроде:

if (getListView().getLastVisiblePosition() == (adapter.items.size() - 1))

Ответ 4

Как я это сделал:

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) {

    }
});

Ответ 5

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

Это сработало для меня.

Ответ 6

Это может быть

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

Ответ 7

Было довольно болезненно иметь дело с прокруткой, обнаружением, когда оно закончено, и оно действительно находится в нижней части списка (не ниже видимого экрана) и трижды запускает мой сервис, чтобы получать данные из Интернета. Однако сейчас он работает нормально. Код выглядит следующим образом в интересах любого, кто сталкивается с такой же ситуацией.

ПРИМЕЧАНИЕ. Мне пришлось переместить связанный с адаптером код в onViewCreated вместо onCreate и обнаружить прокрутку в первую очередь следующим образом:

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

Здесь RideListSimpleCursorAdapter.REACHED_THE_END - дополнительная переменная в моем SimpleCustomAdapter, которая устанавливается следующим образом:

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

Только когда оба этих условия встречаются, это означает, что я действительно находится в нижней части списка и что моя служба будет работать только один раз. Если я не поймаю REACHED_THE_END, даже прокрутка назад снова вызывает службу, пока отображается последний элемент.

Ответ 8

canScrollVertically(int direction) работает для всех представлений и, кажется, делает то, что вы просили, с меньшим количеством кода, чем большинство других ответов. Подключите положительное число, и если результат ложный, вы находитесь внизу.

т

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

Ответ 9

Чтобы немного расширить один из приведенных выше ответов, это то, что я должен был сделать, чтобы заставить его работать полностью. Кажется, около 6dp встроенного дополнения внутри ListViews, и onScroll() вызывается, когда список пуст. Это обрабатывает обе эти вещи. Вероятно, это может быть немного оптимизировано, но для большей наглядности написано.

Боковое примечание. Я пробовал несколько разных методов преобразования dp в пиксель, и этот dp2px() был лучшим.

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

Ответ 10

Я не могу комментировать, потому что у меня недостаточно репутации, но в @Ali Imran и @Wroclai ответ я думаю, что чего-то не хватает. С помощью этого фрагмента кода, как только вы обновите preLast, он никогда не будет выполнять журнал снова. В моей конкретной проблеме я хочу выполнять некоторую операцию каждый раз, когда я прокручиваю ее до нижней части, но как только preLast обновляется до LastItem, эта операция никогда не выполняется снова.

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

}

С помощью этого "else" теперь вы можете выполнять свой код (в этом случае Log) каждый раз, когда вы еще раз прокручиваете нижнюю часть.

Ответ 11

Для того, чтобы ваш список вызывал, когда список достигнет последнего, и если произошла ошибка, это не вызовет endoflistview снова. Этот код также поможет в этом сценарии.

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

где LIST_UP_THRESHOLD_VALUE может быть любым целочисленным значением (я использовал 5), когда ваш список прокручивается вверх и, возвращаясь к концу, это снова вызовет конец списка.

Ответ 12

Я нашел очень хороший способ автоматической загрузки следующей страницы таким образом, чтобы не требовался собственный ScrollView (например, требуется принятый ответ).

В ParseQueryAdapter существует метод под названием getNextPageView, который позволяет вам предоставлять собственное пользовательское представление, которое появляется в конце списка, когда загружается больше данных, поэтому он будет запускаться только тогда, когда вы достигнете конца текущего набора страниц (это "load more.." просмотр по умолчанию). Этот метод вызывается только тогда, когда для загрузки данных требуется больше данных, поэтому он отлично подходит для вызова loadNextPage(); Таким образом, адаптер выполняет всю тяжелую работу для вас при определении того, когда новые данные должны быть загружены, и он вообще не будет вызван если вы достигли конца набора данных.

public class YourAdapter extends ParseQueryAdapter<ParseObject> {

..

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

}

Затем внутри вашей активности/фрагмента вам просто нужно установить адаптер, и новые данные будут автоматически обновлены для вас, как магия.

adapter = new YourAdapter(getActivity().getApplicationContext());
adapter.setObjectsPerPage(15);
adapter.setPaginationEnabled(true);
yourList.setAdapter(adapter);

Ответ 13

Чтобы определить, является ли последний элемент полностью видимым, вы можете просто добавить вычисление на нижний вид видимого элемента представления на 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;
    }
}

Ответ 14

Я пошел с:

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

Ответ 15

В методе getView() (класса BaseAdapter -derived) можно проверить, совпадает ли позиция текущего представления с списком элементов в Adapter. Если это так, значит, мы достигли конца/нижней части списка:

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

Ответ 16

Я нахожу лучший способ обнаружить свиток прокрутки списка вниз, сначала определите конец scoll этим
Реализация onScrollListener для обнаружения конца прокрутки в 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 been a scroll which has completed ***/
        /*** do the work! ***/
    }
}

окончательно совместим ответ 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 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");
                }


            }
        }

    };

Ответ 17

Большое спасибо плакатам в stackoverflow! Я объединил некоторые идеи и создал слушателя класса для действий и фрагментов (поэтому этот код более многократно используется, чтобы код быстрее записывался и намного чище).

Все, что вам нужно сделать, когда вы получили мой класс, - это реализовать интерфейс (и, конечно, создать для него метод), который объявлен в моем классе и создать объект этого класса, передающий аргументы.

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

Ответ 18

Вам нужно добавить пустой список нижнего колонтитула xml в listView и определить, отображается ли этот нижний колонтитул.

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

Затем в своем listView прокрутите прослушиватель, вы сделаете это

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

Ответ 19

Если вы установите тег в представлении последнего элемента списка, позже вы можете получить представление с тегом, если представление имеет нулевое значение, потому что представление больше не загружается. Вот так:

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

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

    }
}

тогда, если вам нужно знать, загружен ли последний элемент

View last = yourListView.findViewWithTag("last");
if (last != null) {               
   // do what you want to do
}

Ответ 20

Janwilx72 прав, но min sdk равно 21, поэтому я создаю этот метод:

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

для ScrollOrientation:

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

Возможно, поздно, только для покойников.

Ответ 21

Это прокрутит список вниз до последней записи.

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