android ListView的分组实现方式参照了以下博客链接的实现方式在此基础上修改。
http://wang-peng1.iteye.com/blog/578411
类似实现方法可参照源码----通讯录-PinnedHeaderListView
以下实现方法缺点:
1、Title透明向上时上一分组的最后一个Cell会被看见。
2、SectionedAdapter的实现方式对于ListView中的Cell重用机制处理的不是很好。
3、Title的实现方式是以Bitmap形式绘制,N多个大Title载入后不能保证不内存溢出。
使用AbsoluteLayout+LIstView实现可能更简便。
SectionedAdapter继承自BaseAdapter 实现了多个Adapted的分组。
以上博客地址在滑动后出现分组Title和Cell的布局加载错误。在此基础上做了以下修改。
abstract public class SectionedAdapter extends BaseAdapter { abstract protected View getHeaderView(String caption,int index,View convertView,ViewGroup parent); private List<Section> sections=new ArrayList<Section>(); private static int TYPE_SECTION_HEADER=0; private Context mContext; public SectionedAdapter(Context mContext) { super(); this.mContext = mContext; } public void addSection(String caption, Adapter adapter, int res) { sections.add(new Section(caption, adapter, res)); } @Override public Object getItem(int position) { for (Section section : this.sections) { if (position==0) { return(section); } int size=section.adapter.getCount()+1; if (position<size) { return(section.adapter.getItem(position-1)); } position-=size; } return(null); } @Override public int getCount() { int total=0; for (Section section : this.sections) { total+=section.adapter.getCount()+1; // add one for header } return(total); } @Override public int getViewTypeCount() { int total=1; // one for the header, plus those from sections for (Section section : this.sections) { total+=section.adapter.getViewTypeCount(); } return(total); } @Override public int getItemViewType(int position) { int typeOffset=TYPE_SECTION_HEADER+1; // start counting from here for (Section section : this.sections) { if (position==0) { return(TYPE_SECTION_HEADER); } int size=section.adapter.getCount()+1; if (position<size) { return(typeOffset+section.adapter.getItemViewType(position-1)); } position-=size; typeOffset+=section.adapter.getViewTypeCount(); } return(-1); } public boolean areAllItemsSelectable() { return(false); } @Override public boolean isEnabled(int position) { return(getItemViewType(position)!=TYPE_SECTION_HEADER); } @Override public View getView(int position, View convertView, ViewGroup parent) { int sectionIndex=0; for (Section section : this.sections) { if (position==0) { return(getHeaderView(section.caption, sectionIndex,convertView, parent)); } int size=section.adapter.getCount()+1; if (position<size) { if(convertView!=null && convertView.getTag().equals(section.res)) convertView = section.adapter.getView(position-1, convertView,parent); else { convertView = LayoutInflater.from(mContext).inflate(section.res, null); convertView = section.adapter.getView(position-1, convertView,parent); convertView.setTag(section.res); } return(convertView); } position-=size; sectionIndex++; } return(null); } @Override public long getItemId(int position) { return(position); } class Section { String caption; Adapter adapter; int res; Section(String caption, Adapter adapter,int res) { this.caption=caption; this.adapter=adapter; this.res = res; } } }
StartAct 程序入口在其中实现了SectionedAdapter对Title的加载
public class StartAct extends Activity { /** Called when the activity is first created. */ SectionedAdapter sectionAdapter; UITableView tableView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 数据导入 sectionAdapter = new SectionedAdapter(this) { @Override protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent) { // TODO Auto-generated method stub TextView result=(TextView)convertView; if (result==null || convertView.getTag()!=null && !convertView.getTag().equals("title")) { result=(TextView)getLayoutInflater().inflate(R.layout.header, null); result.setTag("title"); } result.setText(caption); return result; } }; // tableView = new UITableView(this); this.setContentView(tableView); tableView.setAdapter(sectionAdapter); for(int i =0;i<10;i++) { ArrayAdapter<String> a = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new String[] {"1","1","1","1","1"}); sectionAdapter.addSection("Title"+i, a,android.R.layout.simple_list_item_1); } } }
在父类的dispatchDraw方法中重绘Title
public class UITableView extends ListView implements OnScrollListener { private static final int MAX_ALPHA = 255; private TreeMap<String, Bitmap> titlemap; private List<String> keylist; private int Section; private View mHeadView; private Paint mPaint; int titledy; public UITableView(Context context) { super(context); // TODO Auto-generated constructor stub Section = 0; titlemap = new TreeMap<String, Bitmap>(); keylist = new ArrayList<String>(); mPaint = new Paint(); this.setVerticalFadingEdgeEnabled(false); this.setOnScrollListener(this); } /* * (non-Javadoc) * * @see android.widget.ListView#dispatchDraw(android.graphics.Canvas) */ @Override protected void dispatchDraw(Canvas canvas) { // TODO Auto-generated method stub super.dispatchDraw(canvas); if(mHeadView == null) return; canvas.save(); int childid = this.getPositionForView(this.getChildAt(0)); String titlekey = ""; String key = "" + Section; titledy = 0; mPaint.setAlpha(MAX_ALPHA); Log.d("TAG", "childid:" + childid + "----Section:" + Section+"-----index:"+keylist.indexOf(key)); if (childid < Section) { if (keylist.contains(key) && keylist.indexOf(key) > 0) { titlekey = keylist.get(keylist.indexOf(key)-1); } else { titlekey = keylist.get(0); } // 标签移动计算 if(mHeadView.getTop()<=mHeadView.getHeight()) { titledy-=(mHeadView.getHeight()-mHeadView.getTop()); int alpha = (int) (MAX_ALPHA*(mHeadView.getTop()*1.0f/mHeadView.getHeight())); mPaint.setAlpha(alpha); } }else if(childid == Section) { titlekey = keylist.get(keylist.indexOf(key)); titledy = 0; }else if(childid >Section && keylist.indexOf(key)== keylist.size()-1){ titlekey = keylist.get(keylist.size()-1); titledy = 0; } if (titlemap.get(titlekey) != null) canvas.drawBitmap(titlemap.get(titlekey), 0, titledy, mPaint); canvas.restore(); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub for (int i = 0; i < visibleItemCount; i++) { Object obj = this.getAdapter().getItem(firstVisibleItem + i); if (obj.getClass() == SectionedAdapter.Section.class) { if (titlemap.get("" + (firstVisibleItem + i)) == null) { this.getChildAt(i).setDrawingCacheEnabled(true); Bitmap bmp = Bitmap.createBitmap(this.getChildAt(i) .getDrawingCache()); if (!bmp.isRecycled()) { titlemap.put("" + (firstVisibleItem + i), bmp); if (!keylist.contains("" + (firstVisibleItem + i))) { keylist.add("" + (firstVisibleItem + i)); } } this.getChildAt(i).setDrawingCacheEnabled(false); } Section = firstVisibleItem + i; mHeadView = this.getChildAt(i); break; } } } }