listview分组
来源:互联网 发布:php编程代码大全 编辑:程序博客网 时间:2024/05/21 17:43
使用:
PinnedHeaderListView+SectionedBaseAdapter
这是一个开源的框架。
这两个java类可以直接复制到自己的项目里使用。
效果图:
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
- 分组ListView
- Listview分组
- 分组ListView
- ListView 分组
- listview分组
- ListView分组,类似联系人分组
- C# ListView分组显示
- Android ListView列表分组
- android ListView简单分组
- Android ListView分组布局
- ListView 分组完美实现
- Android listView分组
- Android ListView列表分组
- Android ListView列表分组
- WPF,ListView设置分组
- 分组ListView使用技巧
- ListView 分组显示信息
- ListView的分组实现
- Servlet中Cookie
- SGU_390_Tickets(另类数位DP)
- 文件读取
- AsyncTask
- 2.Hibernate三个准备
- listview分组
- Mac 配置mysql 别名 alias
- Java基础四
- 格式符函数printf()、sprintf()、 vprintf()、 vsprintf()、 fprintf() 和 vfprintf()
- vs vc 编译选项
- 几个javascript技巧
- 支持移动端,PC端图片弹出层(支持键盘)
- 【Linux】阻塞信号
- 短信接口