我们在使用ListView的时候,通常会给数据进行分组,然后界面顶端显示一个当前分组的条目悬浮显示。如果下一个组滑动过来,会替换掉前一个标题。我们现在来做一个标题替换时候的挤压效果。效果大体是这个样子:
写这个demo前需要先了解一下SectionIndexer接口中的两个方法,getSectionForPosition(int position); 通过position获取分组的索引号;getPositionForSection(int sectionIndex); 通过section获取该分组的首个position; 现在开始实现这个demo,首先是布局文件,程序的主布局文件比较简单,一个ListView用于显示联系人列表,一个LinearLayout始终在界面顶部显示分组,代码如下:
[AppleScript] 纯文本查看 复制代码 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context="com.hobby.contactsdemo.MainActivity">
<ListView
android:id="@+id/activity_main_lv_contacts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="none"
android:divider="#DDDDDD"
android:dividerHeight="1dp"
></ListView>
<LinearLayout
android:id="@+id/activity_main_lv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#3355ff"
android:orientation="horizontal">
<TextView
android:id="@+id/activity_main_tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#ffffff"
android:padding="8dp"
android:text="A"/>
</LinearLayout>
</RelativeLayout>
然后新建一个布局adapter_contacts_item_layout用来对listview进行填充,这个布局主要分两部分,第一个LinearLayout显示分组,第二个LinearLayout显示联系人名称。
布局文件已经写好了,接下来进行数据填充,我们要获取根据联系人数据并且数据需要按照名称首个字母进行排序,怎样来获取的,联系人数据保存在(/data/data/com.android.providers.contacts/databases/contacts2.db)中的raw_contacts这张表中,这张表中其中有两列phonebook_label和phonebook_bucket,根据这两列进行排序。
相信Adapter部分大家都很熟悉了,我们就不再赘述了,就是把联系人相关的数据展示到界面上,用首字母进行分组,我们重点看分组怎么进行挤压的效果实现。首先我们的分组是在ListView滚动的时候才会碰到一起,所以我们要设置ListView的OnScrollListener,在onScroll方法里面处理。首先我们拿到当前显示的分组,然后拿到下一个将要显示的分组。默认在最上方的TextView里面把分组名字显示出来。
[AppleScript] 纯文本查看 复制代码 /**
* 当前界面第一项对应的分组section
*/
int section = getSectionForPosition(firstVisibleItem);
/**
* 下一个分组对应的首个position
*/
int nextSectionPosition = getPositionForSection(section + 1);
if (firstVisibleItem != lastFirstVisibleItem) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) lvTitle.getLayoutParams();
params.topMargin = 0;
lvTitle.setLayoutParams(params);
tvTitle.setText(String.valueOf(alphabet.charAt(section)));
}
下一个分组对应的首个position如果正好比当前界面第一个position大1的话,说明下一个分组与当前分组进行相碰了,开始出现挤压效果。挤压的时候,上一个可见的View的Bottom值减去标题TextView的高度,得到一个margin值,这个值就是标题的TextView将要往上移动的距离。我们把这个距离设置到TextView 的topMargin上,注意这个Margin值是负的,所以标题会上移。当标题移动距离已经等于标题的高度的时候,相当于下一个组已经把标题完全顶出去了,复原标题即可。[AppleScript] 纯文本查看 复制代码 if (nextSectionPosition == firstVisibleItem + 1) {
View childView = view.getChildAt(0);
if (childView != null) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) lvTitle.getLayoutParams();
int titleHeight = lvTitle.getHeight();
int bottom = childView.getBottom();
if (bottom < titleHeight) {
float disPush = bottom - titleHeight;
params.topMargin = (int) disPush;
lvTitle.setLayoutParams(params);
} else {
if (params.topMargin != 0) {
params.topMargin = 0;
lvTitle.setLayoutParams(params);
}
}
}
}
lastFirstVisibleItem = firstVisibleItem; 整体实现的原理就是根据ListView的滚动不停的判断View的bottom值,也就是底部的坐标,如果坐标值小于了标题高度,就要对标题进行动态的调整以实现挤压的效果。整个项目的代码放入附件。
|