Извините за запутанное название, я не могу выразить проблему очень кратко...
У меня есть приложение Android со списком ListView, в котором используется круговой/ "бесконечный" адаптер, что в основном означает, что я могу прокручивать его вверх или вниз столько, сколько захочу, и элементы будут обтекать, когда он достигнет вершины или снизу, заставляя его казаться пользователю, как будто он вращает бесконечно длинный список (~ 100) повторяющихся предметов.
Точкой этой настройки является выбор пользователем случайного элемента, просто путем вращения/отображения списка и ожидания, чтобы увидеть, где он останавливается. Я уменьшил трение Listview, поэтому он немного ускоряется и дольше, и это, похоже, работает очень хорошо. Наконец, я разместил частично прозрачное изображение поверх ListView, чтобы заблокировать верхний и нижний элементы (с переходом от прозрачного к черному), заставляя его выглядеть так, как будто пользователь "выбирает" элемент посередине, как если бы они были на вращающемся "колесе", которым они управляли, бросая.
Существует одна очевидная проблема: после того, как вы выбрали ListView, он не останавливается на определенном элементе, но он может перестать вращаться между двумя элементами (где первый видимый элемент пока только частично показан). Я хочу избежать этого, потому что в этом случае не очевидно, какой элемент был "случайно выбран".
Короче говоря: после того, как ListView завершил прокрутку после перехода, я хочу, чтобы он остановился на "цельной" строке, а не на частично видимой строке.
В настоящее время я реализовал это поведение, проверив, когда прокрутка остановилась, а затем выберите первый видимый элемент как таковой:
lv = this.getListView();
lv.setFriction(0.005f);
lv.setOnScrollListener(new OnScrollListener() {
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE)
{
if (isAutoScrolling) return;
isAutoScrolling = true;
int pos = lv.getFirstVisiblePosition();
lv.setSelection(pos);
isAutoScrolling = false;
}
}
});
Это работает достаточно хорошо, кроме одной очевидной проблемы... Первый видимый элемент может быть видимым только для пикселя или двух. В этом случае я хочу, чтобы ListView прыгал "вверх" для этих двух пикселей так, чтобы был выбран второй видимый элемент. Вместо этого, конечно, выбирается первый видимый элемент, который означает, что ListView прыгает "вниз" почти целую строку (минус эти два пикселя).
Короче говоря, вместо перехода к первому видимому элементу я хочу, чтобы он переместился к предмету, который больше всего виден. Если первый видимый элемент меньше половины видимого, я хочу, чтобы он переместился ко второму видимому элементу.
Вот иллюстрация, которая, надеюсь, передает мою мысль. Левый список ListView (каждой пары) показывает состояние после прекращения перехода (где он останавливается), а правый ListView показывает, как он выглядит после того, как он совершил "прыжок", выбрав первый видимый элемент. Слева я показываю текущую (неправильную) ситуацию: элемент B едва заметен, но он все еще является первым видимым элементом, поэтому listView перескакивает, чтобы выбрать этот элемент, что не является логичным, поскольку оно должно прокручивать почти всю высоту элемента попасть туда. Было бы гораздо логичнее прокручивать элемент C (который изображен справа), потому что это "ближе".
Изображение http://nickthissen.nl/Images/lv.jpg
Как я могу достичь такого поведения? Единственный способ, о котором я могу думать, - это как-то измерить, какая часть видимого элемента видима. Если это более 50%, я перехожу к этой позиции. Если он меньше 50%, я перехожу к этой позиции + 1. Однако я не знаю, как измерить это...
Есть идеи?