Подтвердить что ты не робот

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

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

Red area is a header viewdragging thumb does not go back to top

4b9b3361

Ответ 1

Это преднамеренное поведение 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 является только нулевым, если вызов onSectionsChanged вызывается, поэтому пусть теперь игнорирует этот путь.

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

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