Просмотр списка привязки к элементу
Я создаю список изображений, используя 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)
, чтобы исправить это странное поведение.