我正在尝试在 iPhone 联系人应用程序中实现类似 iPhone 的滑动标题(按其起始字母对联系人进行分组的滑动标题)类似的效果。
这是我的应用程序的屏幕,我想要实现的是以下内容:
我有一个“指南标题”和三个“标签”用于对列表进行排序。当用户向上滚动列表时,我希望所有内容都向上滚动(指南标题、选项卡、列表)。但是,当标签到达屏幕顶部(并且指南标题将离开屏幕)时,我希望标签停止并停留在那里(保持为“粘性标题”),并且只有列表项滚动为在任何常规列表视图中。
我在列表视图上方有一个视图组(指南标题)。
首先,我想让指南标题根据列表视图的滚动位置调整它的位置。
第一种方法: 我的想法是为列表视图设置一个 onScrollListener 并将指南标题的上边距更改为列表视图中第一项的滚动位置(这将是一个负值)。
逻辑是正确的,但我面临的问题是,当我在列表视图中滚动时,指南标题视图的重绘速度不够快。当列表视图结束时,指南标题视图仅更新(到我更改的顶部边距值)。即使缓慢滚动也不起作用。使指南标题视图或其父视图无效 (invalidate()) 也无济于事,因为它只会向队列发送一个无效请求,但无效和重绘不会立即发生,而是仅在 UI 线程空闲时发生,当用户仍然将手指放在滚动列表视图上时,这似乎不会发生。似乎抛出列表视图会阻塞整个 UI 线程或让它自己忙起来。
所以主要问题是:当用户滚动列表视图时,更改指南标题视图的边距不会立即变得可见。我正在使用它的代码:
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem,
final int visibleItemCount, final int totalItemCount) {
// Get the first list item and check it's scroll position. This will be the value (top), that we also
// use the scroll the header parallel.
View v = mainList.getChildAt(0);
final int top = (v==null)?0:v.getTop();
// This logs the current scroll position of the first list item element/view group.
Log.d("onScroll", "onScroll: " + top);
// Here we finally change the margin (setting a negative margin) to the header element.
((LinearLayout.LayoutParams)(findViewById(R.id.header_container).getLayoutParams())).setMargins(0, top, 0, 0);
// was just a test: invalidating the outer container/view group, doesn't help
// findViewById(R.id.ll_container).invalidate();
}
我确实在 logcat 中看到了我在上面的代码中插入的“onScroll:”日志输出,但是上边距的以下调整只是不可见。
我的第二种方法:是为指南标题+标签使用滚动视图并使用它们。从列表视图的 onScroll 方法中使用 scrollView.scrollTo(0,Math.abs(Math.abs(top)) 从代码中滚动指南标题(然后是滚动视图)确实有效,并且几乎立即显示在屏幕上,但是,当用户非常快速地翻转列表视图时,它不是很准确/稳定——这意味着它会间隔跳跃并且看起来不平滑;它只有在缓慢滚动时才是准确/稳定的。
我现在的问题是:是否有任何最佳实践来实现这种滑动标题效果,更具体:有没有办法在用户仍在滚动列表视图时强制重新绘制指南标题视图(在我第一次提到的方法中)。