4

我正在尝试在 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)) 从代码中滚动指南标题(然后是滚动视图)确实有效,并且几乎立即显示在屏幕上,但是,当用户非常快速地翻转列表视图时,它不是很准确/稳定——这意味着它会间隔跳跃并且看起来不平滑;它只有在缓慢滚动时才是准确/稳定的。

我现在的问题是:是否有任何最佳实践来实现这种滑动标题效果,更具体:有没有办法在用户仍在滚动列表视图时强制重新绘制指南标题视图(在我第一次提到的方法中)。

4

2 回答 2

2

为此,您应该使用一些技巧(afaik 没有现成的此类功能的实现)。
例如,您可以检测视图上的手势,并且

  • 如果当前手势与向下滚动匹配,并且第一个列表项可见,则将标题的大小动画缩小为 0,将选项卡视图的大小缩小为 match_parent。仅当标题不再存在时才开始滚动列表。
  • 如果当前手势匹配向上滚动,并且第一个手势已经可见,则将标题动画扩展为原始大小。

因此,在标题视图上使用动画可能是您的解决方案。

更新
另一种解决方法是扩展您的List(适配器的值数组):
在顶部插入一个新的(虚拟)项目以表示标题,并修改您ListAdaptergetView方法:

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    if (position == 0)
    {
        convertView = inflater.inflate(R.layout.sliding_header, parent, 
            false);
        return convertView;
    }
    //TODO: your original method body comes here
}

其中引用的 xmlR.layout.sliding_header应包含列表的标题布局。

应用到 的自定义OnScrollListener实现ListView会使标题实际上是列表的一个项目不明显,因为它会隐藏滚动条。
您应该将此侦听器添加到您listView的活动onCreate方法中:

listView.setOnScrollListener(new MyScrollListener());

哪里MyScrollListener是:

/**
 * Custom OnScrollListener
 */
private final class MyScrollListener implements OnScrollListener
{
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState)
    {}

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, 
            int visibleItemCount, int totalItemCount)
    {
        if (view.getFirstVisiblePosition() == 0)
            view.setVerticalScrollBarEnabled(false);
        else if (!view.isVerticalScrollBarEnabled())
            view.setVerticalScrollBarEnabled(true);
    }
}
于 2011-05-08T13:52:38.987 回答
0

我认为您也可以尝试使用我的 ExpandAnimation。 http://udinic.wordpress.com/2011/09/03/expanding-listview-items/

只需传递“引导标题”视图的动画类,让动画为您完成工作,在这种情况下不需要滚动,而且很流畅。

于 2011-09-03T17:38:30.430 回答