Android之带group指示器的ExpandableListView(自写)
程序员文章站
2023-10-19 14:04:35
我们都知道android缺省的expandablelistview的group header无法固定在界面上,当向下滚动后,不能对当前显示的那些child 指示出它们归属于...
我们都知道android缺省的expandablelistview的group header无法固定在界面上,当向下滚动后,不能对当前显示的那些child 指示出它们归属于哪个group,在网上搜了很多关于仿手机qq好友分组效果的expandablelistview,发现都不尽如意,于是乎在别人的基础上改进了一点点,其实原理还是差不多的,只是增加了往上挤出去的动画效果,而且更加简单,只不过还是没有完全到达跟qq一样的效果,希望有高手能实现更加逼真的效果,下面我们先看看效果图:
我这里没有把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扩展成一样的效果。
源码下载
我这里没有把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扩展成一样的效果。
源码下载