转载自:http://blog.csdn.net/h7870181/article/details/40400155
楼主是在平板上测试的,图片稍微有点大,大家看看效果就好
接下来贴源码:
PinnedHeaderExpandableListView.Java
要注意的是 在 onGroupClick方法中parent.setSelectedGroup(groupPosition)这句代码的作用是点击分组置顶,
我这边不需要这个效果,QQ也没有用到,所以给注释了,大家如果需要可以解开注释
- package com.xiaos.view;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.AbsListView;
- import android.widget.AbsListView.OnScrollListener;
- import android.widget.ExpandableListAdapter;
- import android.widget.ExpandableListView;
- import android.widget.ExpandableListView.OnGroupClickListener;
- public class PinnedHeaderExpandableListView extends ExpandableListView implements OnScrollListener,OnGroupClickListener {
- public PinnedHeaderExpandableListView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- registerListener();
- }
- public PinnedHeaderExpandableListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- registerListener();
- }
- public PinnedHeaderExpandableListView(Context context) {
- super(context);
- registerListener();
- }
- /**
- * Adapter 接口 . 列表必须实现此接口 .
- */
- public interface HeaderAdapter {
- public static final int PINNED_HEADER_GONE = 0;
- public static final int PINNED_HEADER_VISIBLE = 1;
- public static final int PINNED_HEADER_PUSHED_UP = 2;
- /**
- * 获取 Header 的状态
- * @param groupPosition
- * @param childPosition
- * @return PINNED_HEADER_GONE,PINNED_HEADER_VISIBLE,PINNED_HEADER_PUSHED_UP 其中之一
- */
- int getHeaderState(int groupPosition, int childPosition);
- /**
- * 配置 Header, 让 Header 知道显示的内容
- * @param header
- * @param groupPosition
- * @param childPosition
- * @param alpha
- */
- void configureHeader(View header, int groupPosition,int childPosition, int alpha);
- /**
- * 设置组按下的状态
- * @param groupPosition
- * @param status
- */
- void setGroupClickStatus(int groupPosition, int status);
- /**
- * 获取组按下的状态
- * @param groupPosition
- * @return
- */
- int getGroupClickStatus(int groupPosition);
- }
- private static final int MAX_ALPHA = 255;
- private HeaderAdapter mAdapter;
- /**
- * 用于在列表头显示的 View,mHeaderViewVisible 为 true 才可见
- */
- private View mHeaderView;
- /**
- * 列表头是否可见
- */
- private boolean mHeaderViewVisible;
- private int mHeaderViewWidth;
- private int mHeaderViewHeight;
- public void setHeaderView(View view) {
- mHeaderView = view;
- AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- view.setLayoutParams(lp);
- if (mHeaderView != null) {
- setFadingEdgeLength(0);
- }
- requestLayout();
- }
- private void registerListener() {
- setOnScrollListener(this);
- setOnGroupClickListener(this);
- }
- /**
- * 点击 HeaderView 触发的事件
- */
- private void headerViewClick() {
- long packedPosition = getExpandableListPosition(this.getFirstVisiblePosition());
- int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition);
- if (mAdapter.getGroupClickStatus(groupPosition) == 1) {
- this.collapseGroup(groupPosition);
- mAdapter.setGroupClickStatus(groupPosition, 0);
- }
- else{
- this.expandGroup(groupPosition);
- mAdapter.setGroupClickStatus(groupPosition, 1);
- }
- this.setSelectedGroup(groupPosition);
- }
- private float mDownX;
- private float mDownY;
- /**
- * 如果 HeaderView 是可见的 , 此函数用于判断是否点击了 HeaderView, 并对做相应的处理 ,
- * 因为 HeaderView 是画上去的 , 所以设置事件监听是无效的 , 只有自行控制 .
- */
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (mHeaderViewVisible) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mDownX = ev.getX();
- mDownY = ev.getY();
- if (mDownX <= mHeaderViewWidth && mDownY <= mHeaderViewHeight) {
- return true;
- }
- break;
- case MotionEvent.ACTION_UP:
- float x = ev.getX();
- float y = ev.getY();
- float offsetX = Math.abs(x - mDownX);
- float offsetY = Math.abs(y - mDownY);
- // 如果 HeaderView 是可见的 , 点击在 HeaderView 内 , 那么触发 headerClick()
- if (x <= mHeaderViewWidth && y <= mHeaderViewHeight
- && offsetX <= mHeaderViewWidth && offsetY <= mHeaderViewHeight) {
- if (mHeaderView != null) {
- headerViewClick();
- }
- return true;
- }
- break;
- default:
- break;
- }
- }
- return super.onTouchEvent(ev);
- }
- @Override
- public void setAdapter(ExpandableListAdapter adapter) {
- super.setAdapter(adapter);
- mAdapter = (HeaderAdapter) adapter;
- }
- /**
- *
- * 点击了 Group 触发的事件 , 要根据根据当前点击 Group 的状态来
- */
- @Override
- public boolean onGroupClick(ExpandableListView parent,View v,int groupPosition,long id) {
- if (mAdapter.getGroupClickStatus(groupPosition) == 0) {
- mAdapter.setGroupClickStatus(groupPosition, 1);
- parent.expandGroup(groupPosition);
- //Header自动置顶
- //parent.setSelectedGroup(groupPosition);
- } else if (mAdapter.getGroupClickStatus(groupPosition) == 1) {
- mAdapter.setGroupClickStatus(groupPosition, 0);
- parent.collapseGroup(groupPosition);
- }
- // 返回 true 才可以弹回第一行 , 不知道为什么
- return true;
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mHeaderView != null) {
- measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
- mHeaderViewWidth = mHeaderView.getMeasuredWidth();
- mHeaderViewHeight = mHeaderView.getMeasuredHeight();
- }
- }
- private int mOldState = -1;
- @Override
- protected void onLayout(boolean changed, int left, int top, int right,int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- final long flatPostion = getExpandableListPosition(getFirstVisiblePosition());
- final int groupPos = ExpandableListView.getPackedPositionGroup(flatPostion);
- final int childPos = ExpandableListView.getPackedPositionChild(flatPostion);
- int state = mAdapter.getHeaderState(groupPos, childPos);
- if (mHeaderView != null && mAdapter != null && state != mOldState) {
- mOldState = state;
- mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
- }
- configureHeaderView(groupPos, childPos);
- }
- public void configureHeaderView(int groupPosition, int childPosition) {
- if (mHeaderView == null || mAdapter == null
- || ((ExpandableListAdapter) mAdapter).getGroupCount() == 0) {
- return;
- }
- int state = mAdapter.getHeaderState(groupPosition, childPosition);
- switch (state) {
- case HeaderAdapter.PINNED_HEADER_GONE: {
- mHeaderViewVisible = false;
- break;
- }
- case HeaderAdapter.PINNED_HEADER_VISIBLE: {
- mAdapter.configureHeader(mHeaderView, groupPosition,childPosition, MAX_ALPHA);
- if (mHeaderView.getTop() != 0){
- mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
- }
- mHeaderViewVisible = true;
- break;
- }
- case HeaderAdapter.PINNED_HEADER_PUSHED_UP: {
- View firstView = getChildAt(0);
- int bottom = firstView.getBottom();
- // intitemHeight = firstView.getHeight();
- int headerHeight = mHeaderView.getHeight();
- int y;
- int alpha;
- if (bottom < headerHeight) {
- y = (bottom - headerHeight);
- alpha = MAX_ALPHA * (headerHeight + y) / headerHeight;
- } else {
- y = 0;
- alpha = MAX_ALPHA;
- }
- mAdapter.configureHeader(mHeaderView, groupPosition,childPosition, alpha);
- if (mHeaderView.getTop() != y) {
- mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight + y);
- }
- mHeaderViewVisible = true;
- break;
- }
- }
- }
- @Override
- /**
- * 列表界面更新时调用该方法(如滚动时)
- */
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- if (mHeaderViewVisible) {
- //分组栏是直接绘制到界面中,而不是加入到ViewGroup中
- drawChild(canvas, mHeaderView, getDrawingTime());
- }
- }
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
- final long flatPos = getExpandableListPosition(firstVisibleItem);
- int groupPosition = ExpandableListView.getPackedPositionGroup(flatPos);
- int childPosition = ExpandableListView.getPackedPositionChild(flatPos);
- configureHeaderView(groupPosition, childPosition);
- }
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- }
- }
PinnedHeaderExpandableAdapter.java 适配器
实现了PinnedHeaderExpandableListView中HeaderAdapter接口
- package com.xiaos.adapter;
- import android.content.Context;
- import android.util.SparseIntArray;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseExpandableListAdapter;
- import android.widget.ImageView;
- import android.widget.TextView;
- import com.xiaos.pinnedheaderexpandable.R;
- import com.xiaos.view.PinnedHeaderExpandableListView;
- import com.xiaos.view.PinnedHeaderExpandableListView.HeaderAdapter;
- public class PinnedHeaderExpandableAdapter extends BaseExpandableListAdapter implements HeaderAdapter{
- private String[][] childrenData;
- private String[] groupData;
- private Context context;
- private PinnedHeaderExpandableListView listView;
- private LayoutInflater inflater;
- public PinnedHeaderExpandableAdapter(String[][] childrenData,String[] groupData
- ,Context context,PinnedHeaderExpandableListView listView){
- this.groupData = groupData;
- this.childrenData = childrenData;
- this.context = context;
- this.listView = listView;
- inflater = LayoutInflater.from(this.context);
- }
- @Override
- public Object getChild(int groupPosition, int childPosition) {
- return childrenData[groupPosition][childPosition];
- }
- @Override
- public long getChildId(int groupPosition, int childPosition) {
- return 0;
- }
- @Override
- public View getChildView(int groupPosition, int childPosition,
- boolean isLastChild, View convertView, ViewGroup parent) {
- View view = null;
- if (convertView != null) {
- view = convertView;
- } else {
- view = createChildrenView();
- }
- TextView text = (TextView)view.findViewById(R.id.childto);
- text.setText(childrenData[groupPosition][childPosition]);
- return view;
- }
- @Override
- public int getChildrenCount(int groupPosition) {
- return childrenData[groupPosition].length;
- }
- @Override
- public Object getGroup(int groupPosition) {
- return groupData[groupPosition];
- }
- @Override
- public int getGroupCount() {
- return groupData.length;
- }
- @Override
- public long getGroupId(int groupPosition) {
- return 0;
- }
- @Override
- public View getGroupView(int groupPosition, boolean isExpanded,
- View convertView, ViewGroup parent) {
- View view = null;
- if (convertView != null) {
- view = convertView;
- } else {
- view = createGroupView();
- }
- ImageView iv = (ImageView)view.findViewById(R.id.groupIcon);
- if (isExpanded) {
- iv.setImageResource(R.drawable.btn_browser2);
- }
- else{
- iv.setImageResource(R.drawable.btn_browser);
- }
- TextView text = (TextView)view.findViewById(R.id.groupto);
- text.setText(groupData[groupPosition]);
- return view;
- }
- @Override
- public boolean hasStableIds() {
- return true;
- }
- @Override
- public boolean isChildSelectable(int groupPosition, int childPosition) {
- return true;
- }
- private View createChildrenView() {
- return inflater.inflate(R.layout.child, null);
- }
- private View createGroupView() {
- return inflater.inflate(R.layout.group, null);
- }
- @Override
- public int getHeaderState(int groupPosition, int childPosition) {
- final int childCount = getChildrenCount(groupPosition);
- if (childPosition == childCount - 1) {
- return PINNED_HEADER_PUSHED_UP;
- } else if (childPosition == -1
- && !listView.isGroupExpanded(groupPosition)) {
- return PINNED_HEADER_GONE;
- } else {
- return PINNED_HEADER_VISIBLE;
- }
- }
- @Override
- public void configureHeader(View header, int groupPosition,
- int childPosition, int alpha) {
- String groupData = this.groupData[groupPosition];
- ((TextView) header.findViewById(R.id.groupto)).setText(groupData);
- }
- private SparseIntArray groupStatusMap = new SparseIntArray();
- @Override
- public void setGroupClickStatus(int groupPosition, int status) {
- groupStatusMap.put(groupPosition, status);
- }
- @Override
- public int getGroupClickStatus(int groupPosition) {
- if (groupStatusMap.keyAt(groupPosition)>=0) {
- return groupStatusMap.get(groupPosition);
- } else {
- return 0;
- }
- }
- }
MainActivity.java主Activity
- package com.xiaos.pinnedheaderexpandable;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ExpandableListView;
- import android.widget.ExpandableListView.OnGroupClickListener;
- import com.xiaos.adapter.PinnedHeaderExpandableAdapter;
- import com.xiaos.view.PinnedHeaderExpandableListView;
- public class MainActivity extends Activity{
- private PinnedHeaderExpandableListView explistview;
- private String[][] childrenData = new String[10][10];
- private String[] groupData = new String[10];
- private int expandFlag = -1;//控制列表的展开
- private PinnedHeaderExpandableAdapter adapter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.layout_main);
- initView();
- initData();
- }
- /**
- * 初始化VIEW
- */
- private void initView() {
- explistview = (PinnedHeaderExpandableListView)findViewById(R.id.explistview);
- }
- /**
- * 初始化数据
- */
- private void initData() {
- for(int i=0;i<10;i++){
- groupData[i] = "分组"+i;
- }
- for(int i=0;i<10;i++){
- for(int j=0;j<10;j++){
- childrenData[i][j] = "好友"+i+"-"+j;
- }
- }
- //设置悬浮头部VIEW
- explistview.setHeaderView(getLayoutInflater().inflate(R.layout.group_head,
- explistview, false));
- adapter = new PinnedHeaderExpandableAdapter(childrenData, groupData, getApplicationContext(),explistview);
- explistview.setAdapter(adapter);
- //设置单个分组展开
- //explistview.setOnGroupClickListener(new GroupClickListener());
- }
- class GroupClickListener implements OnGroupClickListener{
- @Override
- public boolean onGroupClick(ExpandableListView parent, View v,
- int groupPosition, long id) {
- if (expandFlag == -1) {
- // 展开被选的group
- explistview.expandGroup(groupPosition);
- // 设置被选中的group置于顶端
- explistview.setSelectedGroup(groupPosition);
- expandFlag = groupPosition;
- } else if (expandFlag == groupPosition) {
- explistview.collapseGroup(expandFlag);
- expandFlag = -1;
- } else {
- explistview.collapseGroup(expandFlag);
- // 展开被选的group
- explistview.expandGroup(groupPosition);
- // 设置被选中的group置于顶端
- explistview.setSelectedGroup(groupPosition);
- expandFlag = groupPosition;
- }
- return true;
- }
- }
- }
布局文件
child.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="40dip"
- android:background="#FFFFFF" >
- <ImageView
- android:id="@+id/groupIcon"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:paddingLeft="10dp"
- android:src="@null" />
- <TextView
- android:id="@+id/childto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingLeft="10dp"
- android:paddingTop="10dip"
- android:textColor="#000000"
- android:textSize="16sp" />
- </LinearLayout>
group_head.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:background="#B8E6FA"
- android:gravity="center_vertical">
- <ImageView
- android:id="@+id/groupIcon"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:contentDescription="@null"
- android:layout_marginLeft="10dp"
- android:src="@drawable/btn_browser2"/>
- <TextView
- android:id="@+id/groupto"
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:textColor="#000000"
- android:textSize="18sp"
- android:gravity="center_vertical|left"/>
- </LinearLayout>
group.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:background="#B8E6FA"
- android:gravity="center_vertical">
- <ImageView
- android:id="@+id/groupIcon"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:contentDescription="@null"
- android:layout_marginLeft="10dp"
- android:src="@drawable/btn_browser"/>
- <TextView
- android:id="@+id/groupto"
- android:layout_width="match_parent"
- android:layout_height="50dp"
- android:textColor="#000000"
- android:textSize="18sp"
- android:gravity="center_vertical|left"/>
- </LinearLayout>
layout_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#F0F0F0"
- android:orientation="vertical" >
- <com.xiaos.view.PinnedHeaderExpandableListView
- android:id="@+id/explistview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginLeft="0.0dip"
- android:cacheColorHint="#00000000"
- android:choiceMode="singleChoice"
- android:drawSelectorOnTop="false"
- android:fastScrollEnabled="false"
- android:footerDividersEnabled="true"
- android:groupIndicator="@null"
- android:scrollbars="vertical"
- android:scrollingCache="true" />
- </LinearLayout>
AndroidManifest.xml
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.xiaos.pinnedheaderexpandable"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="19" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:icon="@drawable/ic_launcher">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
- </manifest>
两张图片:
下载地址: http://download.csdn.net/detail/h7870181/8073677
转载自:http://blog.csdn.net/h7870181/article/details/40400155