欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android之带group指示器的ExpandableListView(自写)

程序员文章站 2023-10-19 14:04:35
我们都知道android缺省的expandablelistview的group header无法固定在界面上,当向下滚动后,不能对当前显示的那些child 指示出它们归属于...
我们都知道android缺省的expandablelistview的group header无法固定在界面上,当向下滚动后,不能对当前显示的那些child 指示出它们归属于哪个group,在网上搜了很多关于仿手机qq好友分组效果的expandablelistview,发现都不尽如意,于是乎在别人的基础上改进了一点点,其实原理还是差不多的,只是增加了往上挤出去的动画效果,而且更加简单,只不过还是没有完全到达跟qq一样的效果,希望有高手能实现更加逼真的效果,下面我们先看看效果图:
Android之带group指示器的ExpandableListView(自写) 
我这里没有把expandablelistview独立出来形成一个新的控件,跟网上很多朋友一样,监听onscrolllistener事件,当group不是在第一个位置时,就把我们头部的那个indicator显示出来,并且让它的view跟当前child所在group的view一样的,然后再增加一个点击关闭组的事件,即达到了简单的仿qq好友分组的效果。
下面我们先来看看主要的布局文件:main.xml,下面那个topgroup的framelayout就是我们的指示器。
复制代码 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<framelayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<expandablelistview
android:id="@+id/expandablelistview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</expandablelistview>
<framelayout
android:id="@+id/topgroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</framelayout>
</framelayout>

其中最重要的是下面这部分:我们监听onsroll这个接口事件,当listview在滑动时,做相应的处理,代码中注释比较多,我这里就不多作说明了。
复制代码 代码如下:

/**
* here is very importance for indicator group
*/
public void onscroll(abslistview view, int firstvisibleitem,
int visibleitemcount, int totalitemcount) {
final expandablelistview listview = (expandablelistview) view;
/**
* calculate point (0,0)
*/
int npos = view.pointtoposition(0, 0);// 其实就是firstvisibleitem
if (npos == adapterview.invalid_position)// 如果第一个位置值无效
return;
long pos = listview.getexpandablelistposition(npos);
int childpos = expandablelistview.getpackedpositionchild(pos);// 获取第一行child的id
int grouppos = expandablelistview.getpackedpositiongroup(pos);// 获取第一行group的id
if (childpos == adapterview.invalid_position) {// 第一行不是显示child,就是group,此时没必要显示指示器
view groupview = listview.getchildat(npos
- listview.getfirstvisibleposition());// 第一行的view
indicatorgroupheight = groupview.getheight();// 获取group的高度
indicatorgroup.setvisibility(view.gone);// 隐藏指示器
} else {
indicatorgroup.setvisibility(view.visible);// 滚动到第一行是child,就显示指示器
}
// get an error data, so return now
if (indicatorgroupheight == 0) {
return;
}
// update the data of indicator group view
if (grouppos != indicatorgroupid) {// 如果指示器显示的不是当前group
madapter.getgroupview(grouppos, listview.isgroupexpanded(grouppos),
indicatorgroup.getchildat(0), null);// 将指示器更新为当前group
indicatorgroupid = grouppos;
log.e(tag, pre + "bind to new group,group position = " + grouppos);
// madapter.hidegroup(indicatorgroupid); // we set this group view
// to be hided
// 为此指示器增加点击事件
indicatorgroup.setonclicklistener(new onclicklistener() {
public void onclick(view v) {
// todo auto-generated method stub
listview.collapsegroup(indicatorgroupid);
}
});
}
if (indicatorgroupid == -1) // 如果此时grop的id无效,则返回
return;
/**
* calculate point (0,indicatorgroupheight) 下面是形成往上推出的效果
*/
int showheight = indicatorgroupheight;
int nendpos = listview.pointtoposition(0, indicatorgroupheight);// 第二个item的位置
if (nendpos == adapterview.invalid_position)// 如果无效直接返回
return;
long pos2 = listview.getexpandablelistposition(nendpos);
int grouppos2 = expandablelistview.getpackedpositiongroup(pos2);// 获取第二个group的id
if (grouppos2 != indicatorgroupid) {// 如果不等于指示器当前的group
view viewnext = listview.getchildat(nendpos
- listview.getfirstvisibleposition());
showheight = viewnext.gettop();
log.e(tag, pre + "update the show part height of indicator group:"
+ showheight);
}
// update group position
marginlayoutparams layoutparams = (marginlayoutparams) indicatorgroup
.getlayoutparams();
layoutparams.topmargin = -(indicatorgroupheight - showheight);
indicatorgroup.setlayoutparams(layoutparams);
}

本文源码下载
最后跟大家分享一下另外一个仿iphone通讯录效果的代码。它是listview的扩展,效果最好。希望有高手能把expandablelistview扩展成一样的效果。
源码下载