iPhone一样滑动标题,或者:如何强制立即重绘上边距变化?

时间:2011-05-08 13:32:18

标签: android android-layout android-ui

我正试图在iPhone联系人应用程序中实现类似iPhone类似滑动标题的类似效果(通过它的起始字母将联系人分组的滑动标题)。

这是我的应用程序的屏幕,我想要实现的目标如下:

enter image description here

我有一个'引导标题'和三个'标签'用于排序列表。当用户向上滚动列表时,我希望所有内容都向上滚动(引导标题,标签,列表)。但是,当标签到达屏幕顶部时(导向标题将从屏幕上消失),我希望标签停止并保持在那里(保持为“粘性标题”),只有列表项滚动为在任何常规列表视图中。

我在列表视图上方有一个视图组(引导标题)。

首先,我希望引导标题根据列表视图的滚动位置调整它的位置。

第一种方法: 我的想法是将onScrollListener设置为列表视图,并将引导标题的上边距更改为列表视图中第一个项目的滚动位置(这将是负值)。

逻辑是正确的,但是我正面临的问题是当我在列表视图中滚动时,引导标题视图没有足够快地重绘。当列表视图fling结束时,引导标题视图仅更新(对于我更改的上边距值)。即使慢速滚动也行不通。使引导标题视图无效(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(顶部))的代码引导标题(这是一个滚动视图)确实有效并且几乎立即显示在屏幕上,但是,当用户非常快速地浏览列表视图时,它不是非常准确/稳定 - 这意味着它会间隔跳跃并且看起来不平滑;当滚动缓慢时它只是准确/稳定。

我现在的问题是:有没有最好的做法来实现这样的滑动标题效果,更具体一点:有没有办法强制在用户静止时重绘引导标题视图滚动列表视图(在我第一次提到的方法中)。

2 个答案:

答案 0 :(得分:2)

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

  • 如果当前手势与a匹配 向下滚动,以及第一个列表项 是可见的,动画收缩 标题大小为0,标签视图为 size to match_parent。开始滚动 仅当标题不是时才显示列表 现在了。
  • 如果当前手势与滚动匹配 起来,第一个已经可见, 动画扩展标题到它的 原始尺寸。

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

<强>更新
另一种解决方法是扩展您的List(适配器的值数组):
在顶部插入一个新的(虚拟)项目作为标题表示,并修改ListAdapter的{​​{1}}方法:

getView

@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 } 引用的xml应包含列表的标题布局。

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

onCreate

其中listView.setOnScrollListener(new MyScrollListener()); 是:

MyScrollListener

答案 1 :(得分:0)

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

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