我们都知道Android缺省的ExpandableListView的group header无法固定在界面上,当向下滚动后,不能对当前显示的那些child 指示出它们归属于哪个group,在网上搜了很多关于仿手机QQ好友分组效果的ExpandableListView,发现都不尽如意,于是乎在别人的基础上改进了一点点,其实原理还是差不多的,只是增加了往上挤出去的动画效果,而且更加简单,只不过还是没有完全到达跟QQ一样的效果,希望有高手能实现更加逼真的效果,下面我们先看看效果图:

    


我这里没有把ExpandableListView独立出来形成一个新的控件,跟网上很多朋友一样,监听OnScrollListener事件,当group不是在第一个位置时,就把我们头部的那个indicator显示出来,并且让它的view跟当前child所在group的view一样的,然后再增加一个点击关闭组的事件,即达到了简单的仿QQ好友分组的效果。

下面我们先来看看主要的布局文件:main.xml,下面那个topGroup的FrameLayout就是我们的指示器。

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <ExpandableListView  
  7.         android:id="@+id/expandableListView"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent" >  
  10.     ExpandableListView>  
  11.   
  12.     <FrameLayout  
  13.         android:id="@+id/topGroup"  
  14.         android:layout_width="match_parent"  
  15.         android:layout_height="wrap_content"  
  16.         android:orientation="vertical" >  
  17.     FrameLayout>  
  18.   
  19. FrameLayout>  


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

[java]  view plain copy
  1. /** 
  2.      * here is very importance for indicator group 
  3.      */  
  4.     public void onScroll(AbsListView view, int firstVisibleItem,  
  5.             int visibleItemCount, int totalItemCount) {  
  6.   
  7.         final ExpandableListView listView = (ExpandableListView) view;  
  8.         /** 
  9.          * calculate point (0,0) 
  10.          */  
  11.         int npos = view.pointToPosition(00);// 其实就是firstVisibleItem  
  12.         if (npos == AdapterView.INVALID_POSITION)// 如果第一个位置值无效  
  13.             return;  
  14.   
  15.         long pos = listView.getExpandableListPosition(npos);  
  16.         int childPos = ExpandableListView.getPackedPositionChild(pos);// 获取第一行child的id  
  17.         int groupPos = ExpandableListView.getPackedPositionGroup(pos);// 获取第一行group的id  
  18.         if (childPos == AdapterView.INVALID_POSITION) {// 第一行不是显示child,就是group,此时没必要显示指示器  
  19.             View groupView = listView.getChildAt(npos  
  20.                     - listView.getFirstVisiblePosition());// 第一行的view  
  21.             indicatorGroupHeight = groupView.getHeight();// 获取group的高度  
  22.             indicatorGroup.setVisibility(View.GONE);// 隐藏指示器  
  23.         } else {  
  24.             indicatorGroup.setVisibility(View.VISIBLE);// 滚动到第一行是child,就显示指示器  
  25.         }  
  26.         // get an error data, so return now  
  27.         if (indicatorGroupHeight == 0) {  
  28.             return;  
  29.         }  
  30.         // update the data of indicator group view  
  31.         if (groupPos != indicatorGroupId) {// 如果指示器显示的不是当前group  
  32.             mAdapter.getGroupView(groupPos, listView.isGroupExpanded(groupPos),  
  33.                     indicatorGroup.getChildAt(0), null);// 将指示器更新为当前group  
  34.             indicatorGroupId = groupPos;  
  35.             Log.e(TAG, PRE + "bind to new group,group position = " + groupPos);  
  36.             // mAdapter.hideGroup(indicatorGroupId); // we set this group view  
  37.             // to be hided  
  38.             // 为此指示器增加点击事件  
  39.             indicatorGroup.setOnClickListener(new OnClickListener() {  
  40.   
  41.                 public void onClick(View v) {  
  42.                     // TODO Auto-generated method stub  
  43.                     listView.collapseGroup(indicatorGroupId);  
  44.                 }  
  45.             });  
  46.         }  
  47.         if (indicatorGroupId == -1// 如果此时grop的id无效,则返回  
  48.             return;  
  49.   
  50.         /** 
  51.          * calculate point (0,indicatorGroupHeight) 下面是形成往上推出的效果 
  52.          */  
  53.         int showHeight = indicatorGroupHeight;  
  54.         int nEndPos = listView.pointToPosition(0, indicatorGroupHeight);// 第二个item的位置  
  55.         if (nEndPos == AdapterView.INVALID_POSITION)// 如果无效直接返回  
  56.             return;  
  57.         long pos2 = listView.getExpandableListPosition(nEndPos);  
  58.         int groupPos2 = ExpandableListView.getPackedPositionGroup(pos2);// 获取第二个group的id  
  59.         if (groupPos2 != indicatorGroupId) {// 如果不等于指示器当前的group  
  60.             View viewNext = listView.getChildAt(nEndPos  
  61.                     - listView.getFirstVisiblePosition());  
  62.             showHeight = viewNext.getTop();  
  63.             Log.e(TAG, PRE + "update the show part height of indicator group:"  
  64.                     + showHeight);  
  65.         }  
  66.   
  67.         // update group position  
  68.         MarginLayoutParams layoutParams = (MarginLayoutParams) indicatorGroup  
  69.                 .getLayoutParams();  
  70.         layoutParams.topMargin = -(indicatorGroupHeight - showHeight);  
  71.         indicatorGroup.setLayoutParams(layoutParams);  
  72.     }  


本文源码下载地址:http://download.csdn.net/detail/weidi1989/5330759

最后跟大家分享一下另外一个仿iPhone通讯录效果的代码。它是ListView的扩展,效果最好。希望有高手能把ExpandableListView扩展成一样的效果。http://download.csdn.net/detail/weidi1989/5330765

更多相关文章

  1. Android(安卓)双缓冲技术
  2. Android事件传递机制(更加深入的了解事件的触发过程)
  3. javascript检查android软键盘隐藏显示
  4. Android(安卓)Accessibility使用及事件流程简介
  5. android RecyclerView一步步打造分组效果、类似QQ分组、折叠菜单
  6. Android实现简单底部导航栏 Android仿微信滑动切换效果
  7. Android(安卓)- 事件模型(dispatchTouchEvent , interceptTouchEvn
  8. 制作一个透明的Activity
  9. Android小项目之五 splash动画效果

随机推荐

  1. android的Touch事件解析(dispatchTouchEve
  2. Android 通过蓝牙控制小车源代码+视频
  3. Parcelable接口的使用(跨进程,Intent传输)
  4. Android(安卓)SDK 更新时连接出现“https
  5. Android 出错提示:Emulator without GPU e
  6. android横竖屏切换处理
  7. 实现ScrollView的嵌套
  8. android集成amazon的相关sdk
  9. Android(安卓)aidl学习笔记-服务端
  10. android开机过程