Android之带group指示器的ExpandableListView

我们都知道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);
	}


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

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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值