android expendableListView教程

来源:互联网 发布:oracle sql 重复数据 编辑:程序博客网 时间:2024/05/02 00:36

本文实现两级标题,一级标题悬浮在顶端,点击之后可缩放二级标题。

看图:


先定义两个实体类,属于包含关系,类似于一级标题包含多个二级标题。

public class Department implements Serializable {private String departmentId;private String departmentName;}

public class GeneralDepartment implements Serializable{<span style="white-space:pre"></span>private String name;private List<Department> departmentList = new ArrayList<Department>();}

最重要的类:

package com.example.expandablelistviewtest;import com.example.expandablelistviewtest.MainActivity.MyExpandableListAdapter;import android.content.Context;import android.graphics.Canvas;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.ExpandableListAdapter;import android.widget.ExpandableListView;import android.widget.ImageView;public class PinnedHeaderExpListView extends ExpandableListView {/** * Adapter interface. The list adapter must implement this interface. */public interface PinnedHeaderAdapter {/** * Pinned header state: don't show the header. 悬浮标题可见状态:0,不可见 */public static final int PINNED_HEADER_GONE = 0;/** * Pinned header state: show the header at the top of the list. * 悬浮标题可见状态:1,可见 */public static final int PINNED_HEADER_VISIBLE = 1;/** * Pinned header state: show the header. If the header extends beyond * the bottom of the first shown element, push it up and clip. * 悬浮标题可见状态:2,上移状态 */public static final int PINNED_HEADER_PUSHED_UP = 2;/** * Configures the pinned header view to match the first visible list * item. *  * @param header *            pinned header view.悬浮标题 * @param position *            position of the first visible list item.listView的第一个可见元素 * @param alpha *            fading of the header view, between 0 and 255.标题颜色变换 */void configurePinnedHeader(View header, int position, int alpha);}private static final int MAX_ALPHA = 255;private MyExpandableListAdapter mAdapter;private View mHeaderView;private boolean mHeaderViewVisible;private int mHeaderViewWidth;private int mHeaderViewHeight;public PinnedHeaderExpListView(Context context) {super(context);}public PinnedHeaderExpListView(Context context, AttributeSet attrs) {super(context, attrs);}public PinnedHeaderExpListView(Context context, AttributeSet attrs,int defStyle) {super(context, attrs, defStyle);}public void setPinnedHeaderView(View view) {mHeaderView = view;// Disable vertical fading when the pinned header is present// TODO change ListView to allow separate measures for top and bottom// fading edge;// in this particular case we would like to disable the top, but not the// bottom edge./** * listview的上边和下边有黑色的阴影。setFadingEdgeLength(0)去除。 */if (mHeaderView != null) {setFadingEdgeLength(0);}requestLayout();}@Overridepublic void setAdapter(ExpandableListAdapter adapter) {super.setAdapter(adapter);mAdapter = (MyExpandableListAdapter) adapter;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if (mHeaderView != null) {measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);mHeaderViewWidth = mHeaderView.getMeasuredWidth();mHeaderViewHeight = mHeaderView.getMeasuredHeight();}}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);if (mHeaderView != null) {mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);configureHeaderView(getFirstVisiblePosition());}}/** * animating header pushing *  * @param position */public void configureHeaderView(int position) {final int group = getPackedPositionGroup(getExpandableListPosition(position));// groupIndexint groupView = getFlatListPosition(getPackedPositionForGroup(group));// don't// know// indexif (mHeaderView == null) {return;}ImageView view = (ImageView) mHeaderView.findViewById(R.id.imageView1);if (isGroupExpanded(group)) {// 根据group展开or收缩情况设置图标view.setImageResource(R.drawable.ic_opened);} else {view.setImageResource(R.drawable.ic_closed);}/** * 需要注意的就是HeaderView并没有加入到ExpandableListView的子控件中,所以要重写dispatchDraw函数, * 并在里面绘制HeaderView,这样导致一个问题就是直接在HeaderView上面设置的click监听函数无效, * 所以需要重写onTouchEvent来模拟在HeaderView上的OnClick事件。 */setOnPinnedHeaderClickLisenter(new OnClickListener() {// 设置标题点击触发的事件public void onClick(View header) {if (!expandGroup(group))collapseGroup(group);}});// mHeaderView.setOnClickListener(new OnClickListener() {//// public void onClick(View header) {// if (!expandGroup(group))// collapseGroup(group);// }// });int state, nextSectionPosition = getFlatListPosition(getPackedPositionForGroup(group + 1));if (mAdapter.getGroupCount() == 0) {state = PinnedHeaderAdapter.PINNED_HEADER_GONE;} else if (position < 0) {state = PinnedHeaderAdapter.PINNED_HEADER_GONE;} else if (nextSectionPosition != -1&& position == nextSectionPosition - 1) {state = PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP;} elsestate = PinnedHeaderAdapter.PINNED_HEADER_VISIBLE;switch (state) {case PinnedHeaderAdapter.PINNED_HEADER_GONE: {mHeaderViewVisible = false;break;}case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: {mAdapter.configurePinnedHeader(mHeaderView, group, MAX_ALPHA);if (mHeaderView.getTop() != 0) {mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);}mHeaderViewVisible = true;break;}case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {View firstView = getChildAt(0);if (firstView == null) {if (mHeaderView.getTop() != 0) {mHeaderView.layout(0, 0, mHeaderViewWidth,mHeaderViewHeight);}mHeaderViewVisible = true;break;}int bottom = firstView.getBottom();int itemHeight = 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.configurePinnedHeader(mHeaderView, group, alpha);// выползаниеif (mHeaderView.getTop() != y) {mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight+ y);}mHeaderViewVisible = true;break;}}}@Overrideprotected void dispatchDraw(Canvas canvas) {super.dispatchDraw(canvas);if (mHeaderViewVisible) {drawChild(canvas, mHeaderView, getDrawingTime());}}/************重写ontouch函数,来达到mHeader设置onclick事件的效果***********************/private OnClickListener mPinnedHeaderClickLisenter;public void setOnPinnedHeaderClickLisenter(OnClickListener listener) {mPinnedHeaderClickLisenter = listener;}private float mDownX;private float mDownY;private static final float FINGER_WIDTH = 20;@Overridepublic 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);// 如果在固定标题内点击了,那么触发事件if (x <= mHeaderViewWidth && y <= mHeaderViewHeight&& offsetX <= FINGER_WIDTH && offsetY <= FINGER_WIDTH) {if (mPinnedHeaderClickLisenter != null) {mPinnedHeaderClickLisenter.onClick(mHeaderView);}return true;}break;default:break;}}return super.onTouchEvent(ev);}}


Activity类:

package com.example.expandablelistviewtest;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.BaseExpandableListAdapter;import android.widget.ExpandableListView;import android.widget.ImageView;import android.widget.TextView;import com.example.expandablelistviewtest.PinnedHeaderExpListView.PinnedHeaderAdapter;public class MainActivity extends Activity {MyExpandableListAdapter mAdapter;PinnedHeaderExpListView elv;private int mPinnedHeaderBackgroundColor = R.color.red;private int mPinnedHeaderTextColor;private List<GeneralDepartment> generalList;private List<Department> deptList;public void initData() {generalList = new ArrayList<GeneralDepartment>();deptList = new ArrayList<Department>();Department dep1 = new Department("1", "dep1");Department dep2 = new Department("2", "dep2");Department dep3 = new Department("3", "dep3");Department dep4 = new Department("4", "dep4");Department dep5 = new Department("5", "dep5");deptList.add(dep1);deptList.add(dep2);deptList.add(dep3);deptList.add(dep4);deptList.add(dep5);GeneralDepartment generalDep1 = new GeneralDepartment();generalDep1.setName("genDep1");generalDep1.setDepartmentList(deptList);GeneralDepartment generalDep2 = new GeneralDepartment();generalDep2.setName("genDep2");generalDep2.setDepartmentList(deptList);GeneralDepartment generalDep3 = new GeneralDepartment();generalDep3.setName("genDep3");generalDep3.setDepartmentList(deptList);GeneralDepartment generalDep4 = new GeneralDepartment();generalDep4.setName("genDep4");generalDep4.setDepartmentList(deptList);GeneralDepartment generalDep5 = new GeneralDepartment();generalDep5.setName("genDep5");generalDep5.setDepartmentList(deptList);generalList.add(generalDep1);generalList.add(generalDep2);generalList.add(generalDep3);generalList.add(generalDep4);generalList.add(generalDep5);}public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initData();// Set up our adaptermAdapter = new MyExpandableListAdapter();elv = (PinnedHeaderExpListView) findViewById(R.id.list);elv.setAdapter(mAdapter);mPinnedHeaderTextColor = getResources().getColor(R.color.deep_color);elv.setGroupIndicator(null);// 去除自带的展开图标View h = LayoutInflater.from(this).inflate(R.layout.header,(ViewGroup) findViewById(R.id.root), false);elv.setPinnedHeaderView(h);elv.setOnScrollListener((OnScrollListener) mAdapter);}/** * A simple adapter which maintains an ArrayList of photo resource Ids. Each * photo is displayed as an image. This adapter supports clearing the list * of photos and adding a new photo. *  */public class MyExpandableListAdapter extends BaseExpandableListAdapterimplements PinnedHeaderAdapter, OnScrollListener {public Object getChild(int groupPosition, int childPosition) {return generalList.get(groupPosition).getDepartmentList().get(childPosition);}public long getChildId(int groupPosition, int childPosition) {return childPosition;}public int getChildrenCount(int groupPosition) {return generalList.get(groupPosition).getDepartmentList().size();}public View getChildView(int arg0, int arg1, boolean isLastChild,View convertView, ViewGroup parent) {TextView childTextView;View v = convertView;if (v == null) {v = LayoutInflater.from(MainActivity.this).inflate(R.layout.doctors_search_section_item, null);childTextView = (TextView) v.findViewById(R.id.textSection);v.setTag(childTextView);} else {childTextView = (TextView) v.getTag();}childTextView.setText(generalList.get(arg0).getDepartmentList().get(arg1).getDepartmentName());return v;}public Object getGroup(int groupPosition) {return generalList.get(groupPosition);}public int getGroupCount() {return generalList.size();}public long getGroupId(int groupPosition) {return groupPosition;}public View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {View v = convertView;GroupViewHolder h;if (v == null) {v = LayoutInflater.from(MainActivity.this).inflate(R.layout.header, null);h = new GroupViewHolder(v);v.setTag(h);} else {h = (GroupViewHolder) v.getTag();}h.textView.setText(generalList.get(groupPosition).getName());h.imageView.setImageResource(R.drawable.ic_closed);if (isExpanded) {h.imageView.setImageResource(R.drawable.ic_opened);}return v;}class GroupViewHolder {public GroupViewHolder(View v) {this.textView = (TextView) v.findViewById(R.id.textDept);this.imageView = (ImageView) v.findViewById(R.id.imageView1);}private TextView textView;private ImageView imageView;}public boolean isChildSelectable(int groupPosition, int childPosition) {return true;}public boolean hasStableIds() {return true;}/** * размытие/пропадание хэдера */public void configurePinnedHeader(View v, int position, int alpha) {TextView header = (TextView) v.findViewById(R.id.textDept);ImageView image = (ImageView) v.findViewById(R.id.imageView1);final String title = ((GeneralDepartment) getGroup(position)).getName();header.setText(title);// if (alpha == 255) {// header.setBackgroundColor(mPinnedHeaderBackgroundColor);// header.setTextColor(mPinnedHeaderTextColor);// } else {// header.setBackgroundColor(Color.argb(alpha,// Color.red(mPinnedHeaderBackgroundColor),// Color.green(mPinnedHeaderBackgroundColor),// Color.blue(mPinnedHeaderBackgroundColor)));// header.setTextColor(Color.argb(alpha,// Color.red(mPinnedHeaderTextColor),// Color.green(mPinnedHeaderTextColor),// Color.blue(mPinnedHeaderTextColor)));// }}public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {if (view instanceof PinnedHeaderExpListView) {((PinnedHeaderExpListView) view).configureHeaderView(firstVisibleItem);}}public void onScrollStateChanged(AbsListView view, int scrollState) {// TODO Auto-generated method stub}}}



0 0