Android中使用ListView绘制自定义表格(3)

把自定义表格又改进了一下,可以支持行合并。表格分为简单和复杂两种模式

1、简单模式就是《Android中使用ListView绘制自定义表格(2)》描述的方式。不支持行合并

2、复杂模式支持行列合并

1、基于上回上传的代码,改动文件如下

package csdn.danielinbiti.custometableview.item;

public class ItemCell {
	private String cellValue = "";//单元格的值
	private int cellSpan = 1; //单元格跨列
	private CellTypeEnum cellType = CellTypeEnum.LABEL; //单元格类型
	private int colNum = 0;  //单元格列号,从0开始
	private int rowNum = 0;//从0开始,每个item都从0开始
	private int rowSpan = 1;//单元格跨行
	//private int rowType = 0; //行类型

	private boolean isChange = false;//是否被编辑
	public ItemCell(String cellValue,CellTypeEnum cellType,int cellSpan){
		this.cellValue = cellValue;
		this.cellType = cellType;
		this.cellSpan = cellSpan;
	}
	public ItemCell(String cellValue, CellTypeEnum cellType){
		this(cellValue,cellType,1);
	}
	public int getColNum(){
		return this.colNum;
	}
//	public void setRowType(int rowType){
//		this.rowType = rowType;
//	}
//	public int getRowType(){
//		return this.rowType;
//	}
	public String getCellValue(){
		return cellValue;
	}
	public void setCellValue(String value){
		this.cellValue = value;
	}
	public CellTypeEnum getCellType(){
		return cellType;
	}
	public int getCellSpan(){
		return cellSpan;
	}
	public void setIsChange(boolean isChange){
		this.isChange = isChange;
	}
	public boolean getIsChange(){
		return this.isChange;
	}
	//设置行列位置,列根据前面列+rowspan数字累加后的值,rownum每行都从0开始
    public void setPos(int rowNum,int colNum,int rowSpan){
    	this.rowNum = rowNum;
    	this.colNum = colNum;
    	this.rowSpan = rowSpan;
    }
	public int getRowNum() {
		return rowNum;
	}
	public int getRowSpan() {
		return rowSpan;
	}
    public int getId(){
    	return this.rowNum * 10000 + this.rowSpan;
    }
}

CustomeTableItem.java

package csdn.danielinbiti.custometableview.item;

import java.util.ArrayList;
import java.util.HashMap;

import csdn.danielinbiti.custometableview.R;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.LinearLayout.LayoutParams;

public class CustomeTableItem extends LinearLayout {
	private Context context = null;
	private boolean isRead = false;//是否只读
	private ArrayList<View> viewList = new ArrayList();//行的表格列表
	private HashMap<String,View> viewMap = new HashMap();//key为行列组合
	private int[] headWidthArr = null;//表头的列宽设置
	private String rowType = "0";//行的样式id
	private int rowHeight = 0;
	private boolean isSimple = true;//是否简单的行模式(没有行合并)

	public CustomeTableItem(Context context) {
		super(context);
	}
	public CustomeTableItem(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	public CustomeTableItem(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}
	/*
	 * rowType:行的样式,字符任意,相同样式的行不需要再创建了
	 * itemCells:单元格信息
	 * headWidthArr:每列宽度
	 * isRead:是否只读,如果是只读,则所有的输入都不生效
	 */
    public void buildItem(Context context,String rowType,ArrayList<ItemCell> itemCells
    		,int[] headWidthArr,boolean isRead){
    	if(this.getTag()!=null
    			&& this.getTag() instanceof String
    			&& this.getTag().equals("2")){//设置成2为复杂的行合并
    		this.isSimple = false;
    	}
		this.setOrientation(LinearLayout.VERTICAL);//第一层布局垂直
    	this.context = context;
    	this.headWidthArr =headWidthArr.clone();
        this.rowType = rowType;
        if(rowHeight==0){
        	rowHeight = Dp2Px(context,40);
        }
        if(isSimple){
        	this.addCell(itemCells);
        }else{
        	this.addCellR(itemCells);
        }
    }
    private void addCell(ArrayList<ItemCell> itemCells){
    	this.removeAllViews();
    	LinearLayout secondLayout = new LinearLayout(context);
		secondLayout.setOrientation(LinearLayout.HORIZONTAL);
		secondLayout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
		this.addView(secondLayout);
    	int cellIndex = 0;

    	for(int i=0;i<itemCells.size();i++){
    		ItemCell itemCell = itemCells.get(i);
			int endIndex = cellIndex+itemCell.getCellSpan();//所占行数

			int width = getCellWidth(cellIndex,endIndex);//行宽度
			cellIndex = endIndex;
	    	if(itemCell.getCellType()==CellTypeEnum.STRING){
	    		EditText view= (EditText)getInputView();
				view.setText(itemCell.getCellValue());
				view.setWidth(width);
				this.setEditView(view);
				secondLayout.addView(view);
				viewList.add(view);
	    	}else if(itemCell.getCellType()==CellTypeEnum.DIGIT){
	    		EditText view= (EditText)getInputView();
				view.setText(itemCell.getCellValue());
				view.setWidth(width);
				this.setEditView(view);
				this.setOnKeyBorad(view);
				secondLayout.addView(view);
				viewList.add(view);
	    	}else if(itemCell.getCellType()==CellTypeEnum.LABEL){
	    		TextView view = (TextView)getLabelView();
				view.setText(itemCell.getCellValue());
				view.setWidth(width);
				secondLayout.addView(view);
				viewList.add(view);
	    	}
	    	if(i!=itemCells.size()-1){//插入竖线
				LinearLayout v_line = (LinearLayout)getVerticalLine();
				v_line.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
				secondLayout.addView(v_line);
			}
    	}
    }
    private void addCellR(ArrayList<ItemCell> itemCells){
    	this.removeAllViews();
    	RelativeLayout secondLayout = new RelativeLayout(context);
		//secondLayout.setOrientation(LinearLayout.HORIZONTAL);
		secondLayout.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
		this.addView(secondLayout);
    	//int cellIndex = 0;
    	for(int i=0;i<itemCells.size();i++){
    		ItemCell itemCell = itemCells.get(i);
			int endIndex = itemCell.getColNum()+itemCell.getCellSpan();//所占行数

			int width = getCellWidth(itemCell.getColNum(),endIndex);//行宽度
			int height = getCellHeight(itemCell.getRowSpan());
			int left =  this.getCellLeft(itemCell.getColNum());
			int top =  this.getCellTop(itemCell.getRowNum());	

	    	RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
	    	rl.leftMargin = left;
	    	rl.topMargin = top;
	    	if(itemCell.getCellType()==CellTypeEnum.STRING){
	    		EditText view= (EditText)getInputView();
				view.setText(itemCell.getCellValue());
				view.setWidth(width);
				view.setHeight(height);
				this.setEditView(view);
				secondLayout.addView(view,rl);
				viewMap.put(itemCell.getId()+"", view);
	    	}else if(itemCell.getCellType()==CellTypeEnum.DIGIT){
	    		EditText view= (EditText)getInputView();
				view.setText(itemCell.getCellValue());
				view.setWidth(width);
				view.setHeight(height);
				this.setEditView(view);
				this.setOnKeyBorad(view);
				secondLayout.addView(view,rl);
				viewMap.put(itemCell.getId()+"", view);
	    	}else if(itemCell.getCellType()==CellTypeEnum.LABEL){
	    		TextView view = (TextView)getLabelView();
				view.setText(itemCell.getCellValue());
				view.setWidth(width);
				view.setHeight(height);
				secondLayout.addView(view,rl);
				viewMap.put(itemCell.getId()+"", view);
	    	}
//	    	if(i!=itemCells.size()-1){//插入竖线
//				LinearLayout v_line = (LinearLayout)getVerticalLine();
//				v_line.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
//				secondLayout.addView(v_line);
//			}
    	}
    }
    public void refreshData(ArrayList<ItemCell> itemCells){
    	if(this.isSimple){
    		this.refreshDataSimple(itemCells);
    	}else{
    		this.refreshDataR(itemCells);
    	}
    }
    private void refreshDataSimple(ArrayList<ItemCell> itemCells){
		for(int i=0;i<itemCells.size();i++){
			ItemCell itemCell = itemCells.get(i);
			if(itemCell.getCellType()==CellTypeEnum.LABEL){
				TextView view = (TextView)viewList.get(i);
				view.setText(itemCell.getCellValue());
			}else if(itemCell.getCellType()==CellTypeEnum.DIGIT){
				EditText view= (EditText)viewList.get(i);
				view.setText(itemCell.getCellValue());
				this.setEditView(view);
				this.setOnKeyBorad(view);
			}else if(itemCell.getCellType()==CellTypeEnum.STRING){
				EditText view= (EditText)viewList.get(i);
				view.setText(itemCell.getCellValue());
				this.setEditView(view);
			}
		}
	}
    private void refreshDataR(ArrayList<ItemCell> itemCells){
		for(int i=0;i<itemCells.size();i++){
			ItemCell itemCell = itemCells.get(i);
			if(itemCell.getCellType()==CellTypeEnum.LABEL){
				TextView view = (TextView)viewMap.get(itemCell.getId()+"");
				view.setText(itemCell.getCellValue());
			}else if(itemCell.getCellType()==CellTypeEnum.DIGIT){
				EditText view= (EditText)viewMap.get(itemCell.getId()+"");;
				view.setText(itemCell.getCellValue());
				this.setEditView(view);
				this.setOnKeyBorad(view);
			}else if(itemCell.getCellType()==CellTypeEnum.STRING){
				EditText view= (EditText)viewMap.get(itemCell.getId()+"");;
				view.setText(itemCell.getCellValue());
				this.setEditView(view);
			}
		}
	}
    private View getVerticalLine(){
		return LayoutInflater.from(context).inflate(R.layout.atom_line_v_view, null);
	}
    private int getCellWidth(int cellStart,int cellEnd){
		int width = 0;
		for(int i=cellStart;i<cellEnd;i++){
			width = this.headWidthArr[i] + width;
		}
		return width;
	}
    private int getCellLeft(int cellIndex){//从0开始编号
		int left = 0;
		for(int i=0;i<cellIndex;i++){
			left = this.headWidthArr[i] + left;
		}
		return left;
	}
    private int getCellTop(int rowNum){		//rowNum从0开始
		return rowNum*this.rowHeight;
	}
    private int Dp2Px(Context context, float dp) {
	    final float scale = context.getResources().getDisplayMetrics().density;
	    return (int) (dp * scale + 0.5f);
	}
    private int getCellHeight(int rowSpan){
		return rowSpan * this.rowHeight;
	}
    private View getLabelView(){
		return (View)LayoutInflater.from(context).inflate(R.layout.atom_text_view, null);
	}
	private View getInputView(){
		return (View)LayoutInflater.from(context).inflate(R.layout.atom_edttxt_view, null);
	}
	private void setEditView(EditText edtText1){
    	if(this.isRead){
    		edtText1.setEnabled(false);
    	}else{

    	}
	}
	private void setOnKeyBorad(EditText edtText1){
		//数字键盘
		if(!this.isRead){//非只读

		}
	}
	public String getRowType() {
		return rowType;
	}
}

2、简单模式和复杂模式可以通过布局文件配置。不进行设置默认是简单模式

<?xml version="1.0" encoding="utf-8"?>
<csdn.danielinbiti.custometableview.item.CustomeTableItem android:id="@+id/custome_item"
        xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center_vertical"
       android:tag="1"
       android:gravity="center_vertical"
/>

android:tag="2"为复杂模式,不进行配置为简单模式

3、测试数据格式

private void testAddContentRows(HashMap contentMap){
		HashMap rowMap1 = new HashMap();
		lists.add(rowMap1);
		this.testAddRows(rowMap1, 1, "r1-1-1(1)", CellTypeEnum.LABEL,0,0,1);
		this.testAddRows(rowMap1, 1, "r1-2-1(1)", CellTypeEnum.LABEL,1,0,1);
		this.testAddRows(rowMap1, 1, "r1-1-2(1)", CellTypeEnum.STRING,0,1,2);
		this.testAddRows(rowMap1, 2, "r1-1-3(2)", CellTypeEnum.STRING,0,2,2);
		this.testAddRows(rowMap1, 1, "r1-1-4(1)", CellTypeEnum.DIGIT,0,4,2);//注意这个列号的标识,必须是前面列号+跨行数
		rowMap1.put("rowtype", "css1");//表样标示放在内容添加后再添加

		HashMap rowMap2 = new HashMap();
		lists.add(rowMap2);
		this.testAddRows(rowMap2, 1, "r2-1-1(1)", CellTypeEnum.LABEL,0,0,1);
		this.testAddRows(rowMap2, 1, "r2-2-1(1)", CellTypeEnum.LABEL,1,0,1);
		this.testAddRows(rowMap2, 1, "r2-1-2(2)", CellTypeEnum.STRING,0,1,2);
		this.testAddRows(rowMap2, 2, "r2-1-3(1)", CellTypeEnum.STRING,0,2,1);
		this.testAddRows(rowMap2, 2, "r2-2-3(1)", CellTypeEnum.STRING,1,2,1);
		this.testAddRows(rowMap2, 1, "r2-1-4(1)", CellTypeEnum.DIGIT,0,4,2);
		rowMap2.put("rowtype", "css2");//表样标示放在内容添加后再添加

		HashMap rowMap3 = new HashMap();
		lists.add(rowMap3);
		this.testAddRows(rowMap3, 1, "r3-1-1(1)", CellTypeEnum.LABEL,0,0,1);
		this.testAddRows(rowMap3, 1, "r3-2-1(1)", CellTypeEnum.LABEL,1,0,1);
		this.testAddRows(rowMap3, 1, "r3-2-1(1)", CellTypeEnum.LABEL,2,0,1);
		this.testAddRows(rowMap3, 1, "r3-1-2(2)", CellTypeEnum.STRING,0,1,3);
		this.testAddRows(rowMap3, 2, "r3-1-3(1)", CellTypeEnum.STRING,0,2,1);
		this.testAddRows(rowMap3, 2, "r3-2-3(1)", CellTypeEnum.STRING,1,2,1);
		this.testAddRows(rowMap3, 2, "r3-2-3(1)", CellTypeEnum.STRING,2,2,1);
		this.testAddRows(rowMap3, 1, "r3-1-4(1)", CellTypeEnum.DIGIT,0,4,3);
		rowMap3.put("rowtype", "css3");//表样标示放在内容添加后再添加

		HashMap rowMap4 = new HashMap();
		lists.add(rowMap4);
		this.testAddRows(rowMap4, 1, "r4-1-1(1)", CellTypeEnum.LABEL,0,0,1);
		this.testAddRows(rowMap4, 1, "r4-2-1(1)", CellTypeEnum.LABEL,1,0,1);
		this.testAddRows(rowMap4, 1, "r4-2-1(1)", CellTypeEnum.LABEL,2,0,1);
		this.testAddRows(rowMap4, 1, "r4-1-2(2)", CellTypeEnum.STRING,0,1,3);
		this.testAddRows(rowMap4, 2, "r4-1-3(1)", CellTypeEnum.STRING,0,2,1);
		this.testAddRows(rowMap4, 2, "r4-2-3(1)", CellTypeEnum.STRING,1,2,1);
		this.testAddRows(rowMap4, 2, "r4-2-3(1)", CellTypeEnum.STRING,2,2,1);
		this.testAddRows(rowMap4, 1, "r4-1-4(1)", CellTypeEnum.DIGIT,0,4,3);
		rowMap4.put("rowtype", "css3");//表样标示放在内容添加后再添加
	}
private void testAddRows(HashMap rowMap,int colSpan,String cellValue,CellTypeEnum cellType,int rowNum,int colNum,int rowSpan){
	    ItemCell itemCell = new ItemCell(cellValue,cellType,colSpan);
	    itemCell.setPos(rowNum, colNum, rowSpan);
	    rowMap.put(rowMap.size()+"", itemCell);
	}
		//this.testAddContent(contentMap);//简单模式,原来的代码,改行替换成下面代码就可以
		this.testAddContentRows(contentMap);//复杂模式

基于listview方式的动态布局已经实现了行列合并模式,基本也就告一段落了,希望能够给后面的人提供帮助。至于一些样式的设置,这里没有具体提供,包括数字输入时的数字键盘,输入改变时数据获取等方式都没有提供,这些只能使用的人自己根据需要进行加减了。

建议对于最好弄个简单的html之类的布局设计器,这样生成能够使用的数据相对比较好点,要不人工计算数据很容易出错。

源码参见自定义表格(2) ,改动的代码已经在上面都贴出来了。

时间: 2024-10-23 03:43:03

Android中使用ListView绘制自定义表格(3)的相关文章

Android中使用ListView绘制自定义表格(2)

上回再写了<Android中使用ListView绘制自定义表格>后,很多人留言代码不全和没有数据样例.但因为项目原因,没法把源码全部贴上来.近两天,抽空简化了一下,做了一个例子. 效果图如 一.功能: 1.支持列合并 2.考虑了界面刷新优化 3.预留部分接口 4.支持左右滚动 1.枚举类:CellTypeEnum package csdn.danielinbiti.custometableview.item; public enum CellTypeEnum { STRING //字符 ,DI

【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree. 每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己. 因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制. 绘制是一个两遍(two pass)的过程:一个mea

Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree. 每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己. 因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制. 绘制是一个两遍(two pass)的过程:一个mea

Android中View的绘制过程 onMeasure方法简述

Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree. 每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己. 因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制. 绘制是一个两遍(two pass)的过程:一个mea

Android 中View的绘制机制源码分析 一

尊重原创: http://blog.csdn.net/yuanzeyao/article/details/46765113 差不多半年没有写博客了,一是因为工作比较忙,二是觉得没有什么内容值得写,三是因为自己越来越懒了吧,不过最近我对Android中View的绘制机制有了一些新的认识,所以想记录下来并分享给大家.在之后的几篇博客中,我会给大家分享如下的内容: 1.View中measure(),layout(),draw()函数执行过程分析,带领大家详细分析View的尺寸测量过程,位置计算,并最终

Android 中View的绘制机制源码分析 三

到目前为止,measure过程已经讲解完了,今天开始我们就来学习layout过程,不过在学习layout过程之前,大家有没有发现我换了编辑器,哈哈,终于下定决心从Html编辑器切换为markdown编辑器,这里之所以使用"下定决心"这个词,是因为毕竟Html编辑器使用好几年了,很多习惯都已经养成了,要改变多年的习惯确实不易,相信这也是还有很多人坚持使用Html编辑器的原因.这也反应了一个现象,当人对某一事物非常熟悉时,一旦出现了新的事物想取代老的事物时,人们都有一种抵触的情绪,做技术的

【转】整理一下Android中的ListView

原文网址:http://sunbofu.blog.51cto.com/6431507/1280441 Android中的listview目测是一个使用频率很高的组件,所以今天来总结一下listview的基础的用法. 一.最基本的绑定 java代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

android如果用ListView做一个表格形式

效果图: 这样来写: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test); ListView list = (ListView)findViewById(R.id.lvLinks); SquareItemAdapter adapter = new SquareItemAdapter(this)

android 中view的绘制过程

view的绘制过程中分别会执行:onMeasure(会多次)计算view的大小,OnLayout(),确定控件的大小和位置 onDraw()绘制view 当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点. 绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree. 每一个ViewGroup负责要求它的每一个孩子被绘制,每一个View负责绘制自己. 因为整个树是按顺序遍历的,所以