我在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
为什么拖动拇指不会滚动到顶部?
答案 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
),而不是使用标题机制?