listview分组

来源:互联网 发布:php编程代码大全 编辑:程序博客网 时间:2024/05/21 17:43

使用:
PinnedHeaderListView+SectionedBaseAdapter

这是一个开源的框架。
这两个java类可以直接复制到自己的项目里使用。

效果图:
listviewgroup

PinnedHeaderListView.java

public class PinnedHeaderListView extends ListView implements OnScrollListener {    private OnScrollListener mOnScrollListener;    public static interface PinnedSectionedHeaderAdapter {        public boolean isSectionHeader(int position);        public int getSectionForPosition(int position);        public View getSectionHeaderView(int section, View convertView, ViewGroup parent);        public int getSectionHeaderViewType(int section);        public int getCount();    }    private PinnedSectionedHeaderAdapter mAdapter;    private View mCurrentHeader;    private int mCurrentHeaderViewType = 0;    private float mHeaderOffset;    private boolean mShouldPin = true;    private int mCurrentSection = 0;    private int mWidthMode;    private int mHeightMode;    public PinnedHeaderListView(Context context) {        super(context);        super.setOnScrollListener(this);    }    public PinnedHeaderListView(Context context, AttributeSet attrs) {        super(context, attrs);        super.setOnScrollListener(this);    }    public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        super.setOnScrollListener(this);    }    public void setPinHeaders(boolean shouldPin) {        mShouldPin = shouldPin;    }    @Override    public void setAdapter(ListAdapter adapter) {        mCurrentHeader = null;        mAdapter = (PinnedSectionedHeaderAdapter) adapter;        super.setAdapter(adapter);    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {        if (mOnScrollListener != null) {            mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);        }        if (mAdapter == null || mAdapter.getCount() == 0 || !mShouldPin || (firstVisibleItem < getHeaderViewsCount())) {            mCurrentHeader = null;            mHeaderOffset = 0.0f;            for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {                View header = getChildAt(i);                if (header != null) {                    header.setVisibility(VISIBLE);                }            }            return;        }        firstVisibleItem -= getHeaderViewsCount();        int section = mAdapter.getSectionForPosition(firstVisibleItem);        int viewType = mAdapter.getSectionHeaderViewType(section);        mCurrentHeader = getSectionHeaderView(section, mCurrentHeaderViewType != viewType ? null : mCurrentHeader);        ensurePinnedHeaderLayout(mCurrentHeader);        mCurrentHeaderViewType = viewType;        mHeaderOffset = 0.0f;        for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {            if (mAdapter.isSectionHeader(i)) {                View header = getChildAt(i - firstVisibleItem);                float headerTop = header.getTop();                float pinnedHeaderHeight = mCurrentHeader.getMeasuredHeight();                header.setVisibility(VISIBLE);                if (pinnedHeaderHeight >= headerTop && headerTop > 0) {                    mHeaderOffset = headerTop - header.getHeight();                } else if (headerTop <= 0) {                    header.setVisibility(INVISIBLE);                }            }        }        invalidate();    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        if (mOnScrollListener != null) {            mOnScrollListener.onScrollStateChanged(view, scrollState);        }    }    private View getSectionHeaderView(int section, View oldView) {        boolean shouldLayout = section != mCurrentSection || oldView == null;        View view = mAdapter.getSectionHeaderView(section, oldView, this);        if (shouldLayout) {            // a new section, thus a new header. We should lay it out again            ensurePinnedHeaderLayout(view);            mCurrentSection = section;        }        return view;    }    private void ensurePinnedHeaderLayout(View header) {        if (header.isLayoutRequested()) {            int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), mWidthMode);            int heightSpec;            ViewGroup.LayoutParams layoutParams = header.getLayoutParams();            if (layoutParams != null && layoutParams.height > 0) {                heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);            } else {                heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);            }            header.measure(widthSpec, heightSpec);            header.layout(0, 0, header.getMeasuredWidth(), header.getMeasuredHeight());        }    }    @Override    protected void dispatchDraw(Canvas canvas) {        super.dispatchDraw(canvas);        if (mAdapter == null || !mShouldPin || mCurrentHeader == null)            return;        int saveCount = canvas.save();        canvas.translate(0, mHeaderOffset);        canvas.clipRect(0, 0, getWidth(), mCurrentHeader.getMeasuredHeight()); // needed        // for        // <        // HONEYCOMB        mCurrentHeader.draw(canvas);        canvas.restoreToCount(saveCount);    }    @Override    public void setOnScrollListener(OnScrollListener l) {        mOnScrollListener = l;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        mWidthMode = MeasureSpec.getMode(widthMeasureSpec);        mHeightMode = MeasureSpec.getMode(heightMeasureSpec);    }    public void setOnItemClickListener(OnItemClickListener listener) {        super.setOnItemClickListener(listener);    }    public static abstract class OnItemClickListener implements AdapterView.OnItemClickListener {        @Override        public void onItemClick(AdapterView<?> adapterView, View view, int rawPosition, long id) {            SectionedBaseAdapter adapter;            if (adapterView.getAdapter().getClass().equals(HeaderViewListAdapter.class)) {                HeaderViewListAdapter wrapperAdapter = (HeaderViewListAdapter) adapterView.getAdapter();                adapter = (SectionedBaseAdapter) wrapperAdapter.getWrappedAdapter();            } else {                adapter = (SectionedBaseAdapter) adapterView.getAdapter();            }            int section = adapter.getSectionForPosition(rawPosition);            int position = adapter.getPositionInSectionForPosition(rawPosition);            if (position == -1) {                onSectionClick(adapterView, view, section, id);            } else {                onItemClick(adapterView, view, section, position, id);            }        }        public abstract void onItemClick(AdapterView<?> adapterView, View view, int section, int position, long id);        public abstract void onSectionClick(AdapterView<?> adapterView, View view, int section, long id);    }}

SectionedBaseAdapter.java

public abstract class SectionedBaseAdapter extends BaseAdapter implements PinnedHeaderListView.PinnedSectionedHeaderAdapter {    private static int HEADER_VIEW_TYPE = 0;    private static int ITEM_VIEW_TYPE = 0;    /**     * Holds the calculated values of @{link getPositionInSectionForPosition}     */    private SparseArray<Integer> mSectionPositionCache;    /**     * Holds the calculated values of @{link getSectionForPosition}     */    private SparseArray<Integer> mSectionCache;    /**     * Holds the calculated values of @{link getCountForSection}     */    private SparseArray<Integer> mSectionCountCache;    /**     * Caches the item count     */    private int mCount;    /**     * Caches the section count     */    private int mSectionCount;    public SectionedBaseAdapter() {        super();        mSectionCache = new SparseArray<Integer>();        mSectionPositionCache = new SparseArray<Integer>();        mSectionCountCache = new SparseArray<Integer>();        mCount = -1;        mSectionCount = -1;    }    @Override    public void notifyDataSetChanged() {        mSectionCache.clear();        mSectionPositionCache.clear();        mSectionCountCache.clear();        mCount = -1;        mSectionCount = -1;        super.notifyDataSetChanged();    }    @Override    public void notifyDataSetInvalidated() {        mSectionCache.clear();        mSectionPositionCache.clear();        mSectionCountCache.clear();        mCount = -1;        mSectionCount = -1;        super.notifyDataSetInvalidated();    }    @Override    public final int getCount() {        if (mCount >= 0) {            return mCount;        }        int count = 0;        for (int i = 0; i < internalGetSectionCount(); i++) {            count += internalGetCountForSection(i);            count++; // for the header view        }        mCount = count;        return count;    }    @Override    public final Object getItem(int position) {        return getItem(getSectionForPosition(position), getPositionInSectionForPosition(position));    }    @Override    public final long getItemId(int position) {        return getItemId(getSectionForPosition(position), getPositionInSectionForPosition(position));    }    @Override    public final View getView(int position, View convertView, ViewGroup parent) {        if (isSectionHeader(position)) {            return getSectionHeaderView(getSectionForPosition(position), convertView, parent);        }        return getItemView(getSectionForPosition(position), getPositionInSectionForPosition(position), convertView, parent);    }    @Override    public final int getItemViewType(int position) {        if (isSectionHeader(position)) {            return getItemViewTypeCount() + getSectionHeaderViewType(getSectionForPosition(position));        }        return getItemViewType(getSectionForPosition(position), getPositionInSectionForPosition(position));    }    @Override    public final int getViewTypeCount() {        return getItemViewTypeCount() + getSectionHeaderViewTypeCount();    }    public final int getSectionForPosition(int position) {        // first try to retrieve values from cache        Integer cachedSection = mSectionCache.get(position);        if (cachedSection != null) {            return cachedSection;        }        int sectionStart = 0;        for (int i = 0; i < internalGetSectionCount(); i++) {            int sectionCount = internalGetCountForSection(i);            int sectionEnd = sectionStart + sectionCount + 1;            if (position >= sectionStart && position < sectionEnd) {                mSectionCache.put(position, i);                return i;            }            sectionStart = sectionEnd;        }        return 0;    }    public int getPositionInSectionForPosition(int position) {        // first try to retrieve values from cache        Integer cachedPosition = mSectionPositionCache.get(position);        if (cachedPosition != null) {            return cachedPosition;        }        int sectionStart = 0;        for (int i = 0; i < internalGetSectionCount(); i++) {            int sectionCount = internalGetCountForSection(i);            int sectionEnd = sectionStart + sectionCount + 1;            if (position >= sectionStart && position < sectionEnd) {                int positionInSection = position - sectionStart - 1;                mSectionPositionCache.put(position, positionInSection);                return positionInSection;            }            sectionStart = sectionEnd;        }        return 0;    }    public final boolean isSectionHeader(int position) {        int sectionStart = 0;        for (int i = 0; i < internalGetSectionCount(); i++) {            if (position == sectionStart) {                return true;            } else if (position < sectionStart) {                return false;            }            sectionStart += internalGetCountForSection(i) + 1;        }        return false;    }    public int getItemViewType(int section, int position) {        return ITEM_VIEW_TYPE;    }    public int getItemViewTypeCount() {        return 1;    }    public int getSectionHeaderViewType(int section) {        return HEADER_VIEW_TYPE;    }    public int getSectionHeaderViewTypeCount() {        return 1;    }    public abstract Object getItem(int section, int position);    public abstract long getItemId(int section, int position);    public abstract int getSectionCount();    public abstract int getCountForSection(int section);    public abstract View getItemView(int section, int position, View convertView, ViewGroup parent);    public abstract View getSectionHeaderView(int section, View convertView, ViewGroup parent);    private int internalGetCountForSection(int section) {        Integer cachedSectionCount = mSectionCountCache.get(section);        if (cachedSectionCount != null) {            return cachedSectionCount;        }        int sectionCount = getCountForSection(section);        mSectionCountCache.put(section, sectionCount);        return sectionCount;    }    private int internalGetSectionCount() {        if (mSectionCount >= 0) {            return mSectionCount;        }        mSectionCount = getSectionCount();        return mSectionCount;    }}

MainActivity.java

public class MainActivity extends AppCompatActivity {    private PinnedHeaderListView listView;    //声明三个list,存放不同header下的item    private List<itemBean> itemsforheader1;    private List<itemBean> itemsforheader2;    private List<itemBean> itemsforheader3;    //声明一个List存放每个itemlist的Key值    private List<Integer> tags;    //使用map,根据每个header存放不同的itemlist    private Map<Integer, List<itemBean>> mMap;    //每个header下面都有一个自己的itemlist,所以我们使用map来存放这些itemlist    //map是以键值对的形式存储数据的,所以每个itemlist我们都需要一个对应的key    //这个key值,我们使用tags来存储    private LHDAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化        listView = (PinnedHeaderListView) findViewById(R.id.mylistview);        //实例化Items数据源        initdata();        //实例化适配器        adapter = new LHDAdapter(this, tags, mMap);        //设置适配器        listView.setAdapter(adapter);    }    //实例化了15个item数据    private void initdata() {        tags = new ArrayList<Integer>();        itemsforheader1 = new ArrayList<itemBean>();        itemsforheader2 = new ArrayList<itemBean>();        itemsforheader3 = new ArrayList<itemBean>();        mMap = new HashMap<Integer, List<itemBean>>();        for (int i = 0; i < 3; i++) {            tags.add(i);        }        for (int i = 0; i < 2; i++) {            itemsforheader1.add(new itemBean("我是一个粉刷匠" + i));        }        for (int i = 0; i < 5; i++) {            itemsforheader2.add(new itemBean("我是一个铁匠" + i));        }        for (int i = 0; i < 15; i++) {            itemsforheader3.add(new itemBean("我是一个木匠" + i));        }        //将这谢数据存放在3个header里        mMap.put(tags.get(0), itemsforheader1);        mMap.put(tags.get(1), itemsforheader2);        mMap.put(tags.get(2), itemsforheader3);    }}

itemBean.java

/** * Created by LHD on 2016/7/9. */public class itemBean {    private String itemname;    public itemBean(String itemname) {        this.itemname = itemname;    }    public String getItemname() {        return itemname;    }    public void setItemname(String itemname) {        this.itemname = itemname;    }}

LHDAdapter.java

/** * Created by LHD on 2016/7/9. */public class LHDAdapter extends SectionedBaseAdapter {    private Context mcontext;    private Map<Integer, List<itemBean>> mMap;    private List<Integer> mtags;    private LayoutInflater inflater;    public LHDAdapter(Context mcontext, List<Integer> tags, Map<Integer, List<itemBean>> maps) {        this.mcontext = mcontext;        this.mtags = tags;        this.mMap = maps;        inflater = LayoutInflater.from(mcontext);    }    @Override    public Object getItem(int section, int position) {        //返回对应header下的item的position        Log.i("LHD", "getItem->section : " + section);        //根据header的位置拿出对应的key,section的值就是header的位置        //根据key拿出对应的itemlist然后根据position拿出对应的item        return mMap.get(mtags.get(section)).get(position);    }    @Override    public long getItemId(int section, int position) {        Log.i("LHD", "getItemId:  " + section + "  position:" + position);        return 0;    }    //这个返回header的数量,我们一共有3个header所以是3    @Override    public int getSectionCount() {        Log.i("LHD", "getSectionCount:  " + mtags.size());        return mtags.size();    }    //这个返回每个header的子item的数量    @Override    public int getCountForSection(int section) {        Log.i("LHD", "getCountForSection:  " + mMap.get(section).size());        return mMap.get(mtags.get(section)).size();    }    @Override    public View getItemView(final int section, final int position, View convertView, ViewGroup parent) {        //初始化每个holder        ViewHolder vh = null;        if (convertView == null) {            vh = new ViewHolder();            convertView = inflater.inflate(R.layout.itemview, null);            vh.textView = (TextView) convertView.findViewById(R.id.tv_item);            vh.fm = (FrameLayout) convertView.findViewById(R.id.f2);            convertView.setTag(vh);        } else {            vh = (ViewHolder) convertView.getTag();        }        vh.textView.setText(mMap.get(section).get(position).getItemname());        if (section == 1 && mMap.get(1).size() > 0) {            //position>0就说明header2里的item不为空            if (position == mMap.get(section).size() - 1) {                Log.i("LHD", "section==" + section);                vh.fm.setVisibility(View.VISIBLE);            } else {                vh.fm.setVisibility(View.GONE);            }        }        convertView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(mcontext, "点击了header" + section + "的第" + position + "个item", Toast.LENGTH_SHORT).show();            }        });        return convertView;    }    //本来我在这个函数里根据不同的section加载不同的header布局    //效果是可以实现,但是在向下滑动的时候就会出现bug,没法实现header2顶替header1    //这个Bug是和源码有关的,而且在header滑动到顶部以后就不支持点击事件了    @Override    public View getSectionHeaderView(final int section, View convertView, ViewGroup parent) {        RelativeLayout view = null;        if (convertView == null) {            view = (RelativeLayout) inflater.inflate(R.layout.header, null);        } else {            view = (RelativeLayout) convertView;        }        //有数据的时候才显示对应的headerview        TextView textview = (TextView) view.findViewById(R.id.header_title);        if (mMap.get(section).size() > 0) {            view.setVisibility(View.VISIBLE);            textview.setText("标题" + mtags.get(section));        } else {            view.setVisibility(View.GONE);        }        view.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(mcontext, "点击了header" + section, Toast.LENGTH_SHORT).show();            }        });        return view;    }    //item的viewholder    private class ViewHolder {        private TextView textView;        private FrameLayout fm;    }}

代码注释的很详细啦

代码下载:
listview分组 - 下载频道 - CSDN.NET
http://download.csdn.net/detail/baidu_31093133/9571748

1 0