仿QQ的ListView:SpinnedHeaderExpandableListView实现

来源:互联网 发布:淘宝靠谱的口红代购 编辑:程序博客网 时间:2024/06/11 18:32

最近项目中遇到了可折叠ListView,但是要在滑动过程中有固定Title,方便用户可以点击全选或者收起展开的List的操作。


自定义ListView:

/** * @author fanlitao */public class PinnedHeaderExpandableListView extends ExpandableListView implements OnScrollListener,        OnGroupClickListener {    public static final int GROUP_COLLAPSE_STATUS = 0;    public static final int GROUP_EXPAND_STATUS = 1;    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();    }    public interface PinnedSectionedHeaderAdapter {        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;        int getSectionHeaderState(int groupPosition, int childPosition);        void configureSectionHeader(View header, int groupPosition, int childPosition, int alpha);        void setGroupClickStatus(int groupPosition, int status);        int getGroupClickStatus(int groupPosition);        void onSectionHeaderCheckBoxClick(View header, int groupPosition);    }    private static final int MAX_ALPHA = 255;    private PinnedSectionedHeaderAdapter mAdapter;    private View mHeaderView;    private boolean mHeaderViewVisible;    private int mHeaderViewWidth;    private int mHeaderViewHeight;    private boolean mGroupEnable = true;    public void setSelectionHeaderView(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);    }    private void headerViewClick() {        long packedPosition = getExpandableListPosition(getFirstVisiblePosition());        int groupPosition = ExpandableListView.getPackedPositionGroup(packedPosition);        if (mAdapter.getGroupClickStatus(groupPosition) == GROUP_EXPAND_STATUS) {            collapseGroup(groupPosition);            mAdapter.setGroupClickStatus(groupPosition, GROUP_COLLAPSE_STATUS);        }        else {            expandGroup(groupPosition);            mAdapter.setGroupClickStatus(groupPosition, GROUP_EXPAND_STATUS);        }        setSelectedGroup(groupPosition);    }    private float mDownX;    private float mDownY;    @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();                    int checkbox = OptimUtils.dip2px(getContext(), 100);                    float offsetX = Math.abs(x - mDownX);                    float offsetY = Math.abs(y - mDownY);                    if ((x <= mHeaderViewWidth - checkbox) && y <= mHeaderViewHeight                            && offsetX <= mHeaderViewWidth && offsetY <= mHeaderViewHeight) {                        if (mHeaderView != null) {                            headerViewClick();                        }                        return true;                    }                    if ((x > mHeaderViewWidth - checkbox) && y <= mHeaderViewHeight                            && (offsetX < checkbox) && offsetY <= mHeaderViewHeight) {                        if (mHeaderView != null) {                            long packedPosition = getExpandableListPosition(this                                    .getFirstVisiblePosition());                            int groupPosition = ExpandableListView                                    .getPackedPositionGroup(packedPosition);                            mAdapter.onSectionHeaderCheckBoxClick(mHeaderView, groupPosition);                        }                        return true;                    }                    break;                default:                    break;            }        }        return super.onTouchEvent(ev);    }    @Override    public void setAdapter(ExpandableListAdapter adapter) {        super.setAdapter(adapter);        mAdapter = (PinnedSectionedHeaderAdapter) adapter;    }    @Override    public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {        if (mGroupEnable) {            if (mAdapter.getGroupClickStatus(groupPosition) == GROUP_COLLAPSE_STATUS) {                mAdapter.setGroupClickStatus(groupPosition, GROUP_EXPAND_STATUS);                parent.expandGroup(groupPosition);                parent.setSelectedGroup(groupPosition);            } else if (mAdapter.getGroupClickStatus(groupPosition) == GROUP_EXPAND_STATUS) {                mAdapter.setGroupClickStatus(groupPosition, GROUP_COLLAPSE_STATUS);                parent.collapseGroup(groupPosition);            }        }        return true;    }    public void setGroupClickEnable(boolean state) {        mGroupEnable = state;    }    @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);        if (mAdapter != null) {            int state = mAdapter.getSectionHeaderState(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.getSectionHeaderState(groupPosition, childPosition);        switch (state) {            case PinnedSectionedHeaderAdapter.PINNED_HEADER_GONE: {                mHeaderViewVisible = false;                break;            }            case PinnedSectionedHeaderAdapter.PINNED_HEADER_VISIBLE: {                mAdapter.configureSectionHeader(mHeaderView, groupPosition, childPosition,                        MAX_ALPHA);                if (mHeaderView.getTop() != 0) {                    mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);                }                mHeaderViewVisible = true;                break;            }            case PinnedSectionedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {                View firstView = getChildAt(0);                int bottom = firstView.getBottom();                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.configureSectionHeader(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) {            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) {    }}


需要在这个ListView的Adapter中,实现SpinnedHeaderExpandableListView定义的接口。

以下是Adapter中的部分实现

    @Override    public int getSectionHeaderState(int groupPosition, int childPosition) {        final int childCount = getChildrenCount(groupPosition);        if (childPosition == childCount - 1) {            return PINNED_HEADER_PUSHED_UP;        }        else if (childPosition == -1 && !mListView.isGroupExpanded(groupPosition)) {            return PINNED_HEADER_GONE;        }        else {            return PINNED_HEADER_VISIBLE;        }    }    @Override    public void configureSectionHeader(View header, int groupPosition, int childPosition, int alpha) {        TextView headerView = (TextView) header.findViewById(R.id.header_type);        ImageView headerIcon = (ImageView) header.findViewById(R.id.junk_icon_header);        GroupBean bean = (GroupBean) getGroup(groupPosition);        headerView.setText(bean.name);        headerIcon.setImageResource(bean.icon);        final ImageView checkView = (ImageView) header.findViewById(R.id.checkbox);        ImageView expandView = (ImageView) header.findViewById(R.id.expand_icon);        expandView.setSelected(bean.isExpand);        int size = mChilds.get(groupPosition).size();        if (size == 0) {            expandView.setVisibility(View.INVISIBLE);            checkView.setVisibility(View.INVISIBLE);        } else {            checkView.setVisibility(View.VISIBLE);            expandView.setVisibility(View.VISIBLE);            SparseArray<AppBean> set = mSelectSet.get(groupPosition);            if (mIsScanFinished) {                checkView.setSelected(set.size() == size);            } else {                checkView.setSelected(mDefaultCheckState);            }        }    }    private HashMap<Integer, Integer> groupStatusMap = new HashMap<Integer, Integer>();    @Override    public void setGroupClickStatus(int groupPosition, int status) {        groupStatusMap.put(groupPosition, status);    }    @Override    public int getGroupClickStatus(int groupPosition) {        if (groupStatusMap.containsKey(groupPosition)) {            return groupStatusMap.get(groupPosition);        }        else {            return 0;        }    }


这样我们就实现了仿QQ的ExpandableListView的效果。虽然还有一些问题,但是大体样子就该是这样。


0 0