参考: http://blog.csdn.net/way_ping_li/article/details/9090793
自定义的ExpandableListView
package com.example.testiphonetreeview; 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 IphoneTreeView extends ExpandableListView implements OnScrollListener, OnGroupClickListener { public IphoneTreeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); registerListener(); } public IphoneTreeView(Context context, AttributeSet attrs) { super(context, attrs); registerListener(); } public IphoneTreeView(Context context) { super(context); registerListener(); } /** * Adapter 接口 . 列表必须实现此接口 . */ public interface IphoneTreeHeaderAdapter { 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 getTreeHeaderState(int groupPosition, int childPosition); /** * 配置 QQHeader, 让 QQHeader 知道显示的内容 * * @param header * @param groupPosition * @param childPosition * @param alpha */ void configureTreeHeader(View header, int groupPosition, int childPosition, int alpha); /** * 设置组按下的状态 * * @param groupPosition * @param status */ void onHeadViewClick(int groupPosition, int status); /** * 获取组按下的状态 * * @param groupPosition * @return */ int getHeadViewClickStatus(int groupPosition); } private static final int MAX_ALPHA = 160; private IphoneTreeHeaderAdapter mAdapter; /** * 用于在列表头显示的 View,mHeaderViewVisible 为 true 才可见 */ private View mHeaderView; /** * 列表头是否可见 */ private boolean mHeaderViewVisible; private int mHeaderViewWidth; private int mHeaderViewHeight; private OnScrollListener mOnScrollListener; 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() { super.setOnScrollListener(this); setOnGroupClickListener(this); } /** * 点击 HeaderView 触发的事件 */ private void headerViewClick() { long packedPosition = getExpandableListPosition(this .getFirstVisiblePosition()); int groupPosition = ExpandableListView .getPackedPositionGroup(packedPosition); if (mAdapter.getHeadViewClickStatus(groupPosition) == 1) { this.collapseGroup(groupPosition); mAdapter.onHeadViewClick(groupPosition, 0); } else { this.expandGroup(groupPosition); mAdapter.onHeadViewClick(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 = (IphoneTreeHeaderAdapter) adapter; } /** * * 点击了 Group 触发的事件 , 要根据根据当前点击 Group 的状态来 */ @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { if (mAdapter.getHeadViewClickStatus(groupPosition) == 0) { parent.expandGroup(groupPosition); mAdapter.onHeadViewClick(groupPosition, 1); } else if (mAdapter.getHeadViewClickStatus(groupPosition) == 1) { parent.collapseGroup(groupPosition); mAdapter.onHeadViewClick(groupPosition, 0); } 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.getTreeHeaderState(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.getTreeHeaderState(groupPosition, childPosition); switch (state) { case IphoneTreeHeaderAdapter.PINNED_HEADER_GONE: { mHeaderViewVisible = false; break; } case IphoneTreeHeaderAdapter.PINNED_HEADER_VISIBLE: { mAdapter.configureTreeHeader(mHeaderView, groupPosition, childPosition, MAX_ALPHA); if (mHeaderView.getTop() != 0) { mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); } mHeaderViewVisible = true; break; } case IphoneTreeHeaderAdapter.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.configureTreeHeader(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) { if(mOnScrollListener!=null){ mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } final long flatPos = getExpandableListPosition(firstVisibleItem); int groupPosition = ExpandableListView.getPackedPositionGroup(flatPos); int childPosition = ExpandableListView.getPackedPositionChild(flatPos); System.out.println("onScroll=============groupPosition: " + groupPosition + ", childPosition: " + childPosition); configureHeaderView(groupPosition, childPosition); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if(mOnScrollListener!=null){ mOnScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void setOnScrollListener(OnScrollListener l) { mOnScrollListener = l; } }
MainActivity.java
package com.example.testiphonetreeview; import java.util.HashMap; import android.app.Activity; import android.os.Bundle; 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.example.testiphonetreeview.IphoneTreeView.IphoneTreeHeaderAdapter; public class MainActivity extends Activity { private IphoneTreeView iphoneTreeView; private LayoutInflater mInflater; private IphoneTreeViewAdapter mAdp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView(){ mInflater = LayoutInflater.from(this); iphoneTreeView = (IphoneTreeView) findViewById(R.id.iphone_tree_view); iphoneTreeView.setHeaderView(getLayoutInflater().inflate( R.layout.contact_buddy_list_group, iphoneTreeView, false)); iphoneTreeView.setGroupIndicator(null); mAdp = new IphoneTreeViewAdapter(); iphoneTreeView.setAdapter(mAdp); } public class IphoneTreeViewAdapter extends BaseExpandableListAdapter implements IphoneTreeHeaderAdapter { // Sample data set. children[i] contains the children (String[]) for // groups[i]. private HashMap<Integer, Integer> groupStatusMap; private String[] groups = { "第一组", "第二组", "第三组", "第四组", "第五组", "第六组", "第七组", "第八组" }; private String[][] children = { { "Way", "Arnold", "Barry", "Chuck", "David", "Afghanistan", "Albania", "Belgium", "Lily", "Jim", "LiMing", "Jodan" }, { "Ace", "Bandit", "Cha-Cha", "Deuce", "Bahamas", "China", "Dominica", "Jim", "LiMing", "Jodan" }, { "Fluffy", "Snuggles", "Ecuador", "Ecuador", "Jim", "LiMing", "Jodan" }, { "Goldy", "Bubbles", "Iceland", "Iran", "Italy", "Jim", "LiMing", "Jodan" }, { "Goldy", "Bubbles", "Iceland", "Iran", "Italy", "Jim", "LiMing", "Jodan" }, { "Goldy", "Bubbles", "Iceland", "Iran", "Italy", "Jim", "LiMing", "Jodan" }, { "Goldy", "Bubbles", "Iceland", "Iran", "Italy", "Jim", "LiMing", "Jodan" }, { "Fluffy", "Bubbles", "Iceland", "Iran", "Italy", "Jim", "LiMing", "Snuggles" }}; public IphoneTreeViewAdapter() { // TODO Auto-generated constructor stub groupStatusMap = new HashMap<Integer, Integer>(); } public Object getChild(int groupPosition, int childPosition) { return children[groupPosition][childPosition]; } public long getChildId(int groupPosition, int childPosition) { return childPosition; } public int getChildrenCount(int groupPosition) { return children[groupPosition].length; } public Object getGroup(int groupPosition) { return groups[groupPosition]; } public int getGroupCount() { return groups.length; } public long getGroupId(int groupPosition) { return groupPosition; } public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } public boolean hasStableIds() { return true; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { // TODO Auto-generated method stub if (convertView == null) { convertView = mInflater.inflate(R.layout.contact_list_item_for_buddy, null); } TextView tv = (TextView) convertView .findViewById(R.id.contact_list_item_name); tv.setText(getChild(groupPosition, childPosition).toString()); TextView state = (TextView) convertView .findViewById(R.id.cpntact_list_item_state); state.setText("爱生活...爱Android..."); return convertView; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { // TODO Auto-generated method stub if (convertView == null) { convertView = mInflater.inflate(R.layout.contact_buddy_list_group, null); } TextView groupName = (TextView) convertView .findViewById(R.id.group_name); groupName.setText(groups[groupPosition]); ImageView indicator = (ImageView) convertView .findViewById(R.id.group_indicator); TextView onlineNum = (TextView) convertView .findViewById(R.id.online_count); onlineNum.setText(getChildrenCount(groupPosition) + "/" + getChildrenCount(groupPosition)); if (isExpanded) { indicator.setImageResource(R.drawable.indicator_expanded); } else { indicator.setImageResource(R.drawable.indicator_unexpanded); } return convertView; } @Override public int getTreeHeaderState(int groupPosition, int childPosition) { final int childCount = getChildrenCount(groupPosition); System.out.println("getTreeHeaderState=============groupPosition: " + groupPosition + ", childPosition: " + childPosition + ", childCount: " + childCount); if (childPosition == childCount - 1) { System.out.println("=================PINNED_HEADER_PUSHED_UP======================"); return PINNED_HEADER_PUSHED_UP; } else if (childPosition == -1 && !iphoneTreeView.isGroupExpanded(groupPosition)) { System.out.println("=================PINNED_HEADER_GONE======================"); return PINNED_HEADER_GONE; } else { System.out.println("=================PINNED_HEADER_VISIBLE======================"); return PINNED_HEADER_VISIBLE; } } @Override public void configureTreeHeader(View header, int groupPosition, int childPosition, int alpha) { // TODO Auto-generated method stub ((TextView) header.findViewById(R.id.group_name)) .setText(groups[groupPosition]); ((TextView) header.findViewById(R.id.online_count)) .setText(getChildrenCount(groupPosition) + "/" + getChildrenCount(groupPosition)); header.getBackground().setAlpha(alpha); } @Override public void onHeadViewClick(int groupPosition, int status) { // TODO Auto-generated method stub groupStatusMap.put(groupPosition, status); } @Override public int getHeadViewClickStatus(int groupPosition) { if (groupStatusMap.containsKey(groupPosition)) { return groupStatusMap.get(groupPosition); } else { return 0; } } } }
布局文件就不贴了,会附上源码,效果图如下