一些想法:
1) 如果你确定要使用ListView,请跳过此点。否则,您可能对原生支持表结构的 GRIDVIEW 感兴趣。
2) 你的想法是一致的。 ListView 只知道 ROWS,因此您的适配器将被调用以显示 ROW,并且由您决定将该行中的数组转换为具有多个单元格的元素。您将在getView() 中执行此操作
3) 您将使用项目类型(getViewTypeCount 和getItemViewType)来声明您有不同的项目类型。每种类型都是具有给定单元格数量的行:1,2,3,4...
- 您将覆盖
getViewTypeCount() 以返回一行中的最大单元格数
- 您可以为静态布局膨胀以获得一行的单元格数量,或者动态生成它
让我们开始吧...首先在适配器中我们重写 Type 方法来声明
我们的行将是不同的类型:
@Override
public int getViewTypeCount() {
return 4;
// you have 4 types of rows.
// SUPER IMPORTANT: No row in the array can have more cells than this number
// or getView will crash (you'd have to define additional layouts)
}
@Override
public int getItemViewType(int position) {
// for a given position, you need to return what type is it. This number ranges
// from 0 to itemtypecount-1. We return the length of the array (number of cells)
// this function is called by the View Recycler to appropriately pass you the
// correct view to reuse in convertView
return myDataArray[position].length - 1;
}
然后我们需要实现getView()。典型的实现将是第一个,您创建不同的 XML,第二个是更高级的实现,我们在没有任何 xml 的情况下动态创建布局。
第一种情况:静态布局
- 如果您将行数组长度限制为 3 或 4,以避免创建数十个布局,这是理想的选择。因此,您定义了 4 个 xml(即
row_1_childs、row_2_childs、row_3_childs、row_4_childs),它们将是具有该数量子级的行的模板。那么,
然后在 GetView 中:
// we define an array of layout ids to quickly select the layout to inflate depending on
// the number of rows:
private final static int[] sLayouts=new int[] {
R.layout.row_1_childs,
R.layout.row_2_childs,
R.layout.row_3_childs,
R.layout.row_4_childs
};
public View getView (int position, View convertView, ViewGroup parent) {
int maxcells=myDataArray[position].length;
if (convertView == null) {
// generate the appropriate type
if (maxcells<=sLayout.length) {
// just check we are in bounds
convertView=LayoutInflater.from(parent.getContext()).inflate(sLayout[maxcells-1], null);
} else {
// you have a row with too many elements, need to define additional layouts
throw new RuntimeException ("Need to define more layouts!!");
}
}
// At this point, convertView is a row of the correct type, either just created,
// or ready to recycle. Just fill in the cells
// for example something like this
ViewGroup container=(ViewGroup)convertView;
for (int i=0; i<maxcells; i++) {
// We assume each row is a (linear)layout whose only children are textviews,
// one for each cell
TextView cell=(TextView)container.getChildAt(i); // get textview for cell i
cell.setText(myDataArray[position][i]);
cell.setTag( new PositionInfo(position, i)); // we store the cell number and row inside the TextView
cell.setOnClickListener(mCellClickListener);
}
return convertView;
}
第二种情况:动态布局
另一种解决方案是动态生成行,并根据需要动态生成尽可能多的文本视图。为此,请继续覆盖 getViewTypeCount() 以返回最大子代数,并像这样定义 getView:
public View getView (int position, View convertView, ViewGroup parent) {
String rowData=myDataArray[position];
if (convertView==null) {
// generate a LinearLayout for number of children:
LinearLayout row=new LinearLayout(context);
for (int i=0, len=rowData.length(); i<len; i++) {
// generate a textview for each cell
TextView cell=new TextView(parent.getContext());
// we will use the same clicklistener (very efficient)
cell.setOnClickListener(mCellClickListener);
row.addView(cell, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1)); // same width for each cell
}
convertView=row;
}
// here convertView has the correct number of children, same as before:
ViewGroup container=(ViewGroup)convertView;
for (int i=0, len=rowData.length(); i<len; i++) {
TextView cell=(TextView)container.getChildAt(i);
cell.setText(rowData[i]);
cell.setTag( new PositionInfo(position, i)); // we store the cell number and row inside the TextView
}
return convertView;
}
// auxiliar class to store row and col in each textview for the clicklistener
private class PositionInfo {
public int row, col;
public PositionInfo(int row, int col) { this.row=row; this.col=col; }
}
// trick: only one clicklistener for millions of cells
private View.OnClickListener mCellClickListener=new View.OnClickListener() {
@Override
public void onClick(View v) {
PositionInfo position=(PositionInfo)v.getTag(); // we stored this previously
// you pressed position.row and position.col
}
}
解决方案 (1) 很酷,可以手动创建布局并进行大量配置。
解决方案 (2) 很酷,可以以编程方式支持任意数量的单元,以防它们非常不同
这两种解决方案都非常有效,因为它们与 View 回收器配合得很好:如果您不使用 View Types 并且不断地膨胀布局,您的 ListView 将会滞后并浪费大量内存和资源。强>