Просмотр списка привязки к элементу

Я создаю список изображений, используя ListView, и фотографии имеют размер, который будет содержать от 2 до 3 фотографий на экране.

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

Есть ли способ добиться этого в android со списком?

Ответы

Ответ 1

Я нашел способ сделать это, просто прослушивая прокрутку и изменив положение, когда прокрутка закончилась, реализовав ListView.OnScrollListener

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
    case OnScrollListener.SCROLL_STATE_IDLE:
        if (scrolling){
            // get first visible item
            View itemView = view.getChildAt(0);
            int top = Math.abs(itemView.getTop()); // top is a negative value
            int bottom = Math.abs(itemView.getBottom());
            if (top >= bottom){
                ((ListView)view).setSelectionFromTop(view.getFirstVisiblePosition()+1, 0);
            } else {
                ((ListView)view).setSelectionFromTop(view.getFirstVisiblePosition(), 0);
            }
        }
        scrolling = false;
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
    case OnScrollListener.SCROLL_STATE_FLING:
        Log.i("TEST", "SCROLLING");
        scrolling = true;
        break;
    }
}

Изменение не так гладко, но оно работает.

Ответ 2

Используя пару идей из решения @nininho, я получил свой список для привязки к элементу с плавным прокруткой, а не внезапным переходом к нему. Одно из предостережений в том, что я тестировал это решение только на Moto X в базовом ListView с текстом, но он отлично работает на устройстве. Тем не менее, я уверен в этом решении и предлагаю вам обратную связь.

listview.setOnScrollListener(new OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            // TODO Auto-generated method stub
            if (scrollState == SCROLL_STATE_IDLE) {
                View itemView = view.getChildAt(0);
                int top = Math.abs(itemView.getTop());
                int bottom = Math.abs(itemView.getBottom());
                int scrollBy = top >= bottom ? bottom : -top;
                if (scrollBy == 0) {
                    return;
                }
                smoothScrollDeferred(scrollBy, (ListView)view);
            }
        }

        private void smoothScrollDeferred(final int scrollByF,
                final ListView viewF) {
            final Handler h = new Handler();
            h.post(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    viewF.smoothScrollBy(scrollByF, 200);
                }
            });
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            // TODO Auto-generated method stub

        }
    });

Причина, по которой я откладываю гладкую прокрутку, заключается в том, что при моем тестировании прямое обращение к методу smoothScrollBy в состоянии измененного обратного вызова имело проблемы с прокруткой. Кроме того, я не предвижу полностью протестированное, надежное решение, поддерживающее очень много состояний, и в моем решении ниже я не имею никакого состояния. Это решение еще не включено в Google Play Store, но оно должно служить хорошей отправной точкой.

Ответ 3

Используя решение @nininho,

В onScrollStateChanged, когда состояние изменится на SCROLL_STATE_IDLE, запомните позицию, чтобы привязать и поднять флаг:

snapTo = view.getFirstVisiblePosition();
shouldSnap = true;

Затем переопределите метод computeScroll():

@Override
public void computeScroll() {
    super.computeScroll();
    if(shouldSnap){
        this.smoothScrollToPositionFromTop(snapTo, 0);
        shouldSnap = false;
    }
}

Ответ 4

Вы можете сделать более плавную прокрутку, если используете RecyclerView. OnScrollListener лучше.

Я привел пример здесь: https://github.com/plattysoft/SnappingList

Ответ 5

Помимо попыток кода выше, вы должны убедиться в том, что ваш listView имеет высоту, которая может соответствовать точному количеству элементов, которые вы хотите отобразить. например Если вам нужно отобразить 4 элемента после эффекта привязки, а высота строки (определенная в ее макете) должна быть 1/4 от общей высоты списка.

Ответ 6

Обратите внимание, что после вызова smoothScrollBy() getFirstVisiblePosition() может указывать на элемент списка ВЫШЕ верхний в списке. Это особенно верно, если view.getChildAt(0).getBottom() == 0. Мне пришлось вызвать view.setSelection(view.getFirstVisiblePosition() + 1), чтобы исправить это странное поведение.