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);
}
}
}
UITableView 继承自ListView。实现OnScrollListener
在父类的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;
}
}
}
}