FastScroller только прокручивает назад к первому элементу, а не к виду заголовка

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

Скриншот 1: красная область на скриншоте – это вид заголовка.
Скриншот 2: Если вы перетаскиваете большой палец вверх, вы получаете только первый элемент, а заголовок все еще выше.

ListView lv = (ListView) findViewById(R.id.listView); lv.addHeaderView(getLayoutInflater().inflate(R.layout.view,null), null, false); 

 <ListView android:layout_height="fill_parent" android:id="@+id/listView" android:layout_width="fill_parent" android:fastScrollEnabled="true" ></ListView> 

Я создал демонстрационный проект: https://github.com/mikegr/fastscroll-bug

Почему перетаскивание большого пальца не прокручивается назад?

Красная область - это вид заголовкаПеретаскивание большого пальца не возвращается

Solutions Collecting From Web of "FastScroller только прокручивает назад к первому элементу, а не к виду заголовка"

Это преднамеренное поведение FastScroller . Когда вы вызываете setAdapter в ListView , адаптер обертывается в HeaderViewListAdapter если есть набор заголовков; Поэтому вы должны вызвать addHeaderView перед setAdapter . Затем в коде FastScroller мы видим:

  if (adapter instanceof HeaderViewListAdapter) { mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount(); adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); } 

То есть, получите смещение и используйте базовый адаптер. mListOffset затем используется для установки верхнего положения для прокрутки с помощью быстрого скроллера. Итак, где же происходит эта упаковка? До, как и ожидалось, ListView.addHeaderView , где мы видим:

  if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } 

Поэтому мы определенно оглядываем правильное место. Теперь, похоже, ваша цель состоит в том, чтобы НЕ иметь поведение смещения для заголовков списков для вашего быстрого большого пальца, но в остальном иметь обычный список с заголовком. Чтобы сделать это, достаточно (на основе того, что мы видели в коде), чтобы FastScroller.mListOffset = 0 . Это устанавливается только в getSectionsFromIndexer , который безоговорочно называется init , и условно в нескольких других функциях, только когда mListAdapter == null . mListAdapter имеет значение null, если onSectionsChanged , поэтому давайте теперь игнорировать этот путь.

После многого рытья и игры с различными крючками отражения я могу сказать, что нет никакого способа сделать это, что будет даже немного совместимо с будущим. Вы можете использовать отражение, чтобы заменить HeaderViewListAdapter тем, что находится вокруг его заголовка, и т. Д .; Но это довольно хрупко. Аналогичным образом, вы можете подклассифицировать (пакет видимый) FastScroller с одним своим поведением; Но mListOffset ссылается широко, а не через геттер, так что это даже уродливее, чем обычно. В основном, вы сталкиваетесь с тем, что система работает не так, как вы хотите.

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