FastScroller仅滚动回第一个元素,而不是标题视图

时间:2011-10-24 12:51:23

标签: android listview android-listview

我在ListView中启用了快速滚动功能,该功能具有无法选择的标题视图。如果向下滚动列表并将快速滚动滑块拖动到顶部,则列表仅向后滚动到第一个元素,而不是向标题视图滚动。拖动列表,按预期工作。

屏幕截图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 view dragging thumb does not go back to top

1 个答案:

答案 0 :(得分:12)

这是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),而不是使用标题机制?