一、背景
在做一些测试的时候经常会用到一些数据用于对比,或者显示多个字段在不同情况下的信息,这时用表格显示非常直观,所以就自定义了一个表格控件。
二、原理
绘制表格需要画直线,设置单元格的背景颜色,设置单元格中字体大小,设置单元格的高度,根据这些需求,我们可以使用View的onDraw()方法中的canvas快速实现,画直线使用canvas.drawLine(),设置单元格背景颜色可以使用canvas.drawRect()和设置Paint对象的填充颜色,设置字体大小可以使用canvas.drawText()和设置Paint对象的颜色,设置单元格宽度和高度要设置两条线起点之间的距离了。
三、实现
demo下载
3.1 继承View,并且重写3个View类的构造方法,最主要的是带3个参数的构造方法
public FormView(Context context) {
this(context, null, 0);
}
public FormView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FormView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Resources resources = context.getResources();
/* 获取自定义属性,R.styleable.FormView是自定义attr */
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FormView);
/* 获取行和列的资源ID,如果没有就为0 */
int fieldsResourceId = typedArray.getResourceId(R.styleable.FormView_fields, 0);
int titlesResourceId = typedArray.getResourceId(R.styleable.FormView_titles, 0);
if(fieldsResourceId != 0) {
String[] strFieleds = resources.getStringArray(fieldsResourceId);
for(String field : strFieleds){
fields.add(field);
}
/* 要增加一行用来显示列标题 */
line = fields.size() + 1;
}
if(titlesResourceId != 0) {
String[] strTitles = resources.getStringArray(titlesResourceId);
for(String title : strTitles){
titles.add(title);
}
column = titles.size();
}
textSize = typedArray.getDimension(R.styleable.FormView_textSize, 20);
/* 初始化列表中每一个单元格的值,都初始化为空 */
for(int j=0; j<fields.size(); j++){
ArrayList<String> values = new ArrayList<>();
/* 第一列是用来显示属性的,所以列表数据列数=titles.size()-1 */
for(int i=0; i<(titles.size() - 1); i++){
values.add("");
}
/* 用一个map保存起来 */
datas.put(fields.get(j), values);
}
/* 用完记得回收 */
typedArray.recycle();
}
R.styleable.FormView来自文件form_view_attr.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FormView">
<attr name="titles" format="reference" /><!--显示在第一行的标题-->
<attr name="fields" format="reference" /><!--显示在第一列的属性-->
<attr name="textSize" format="dimension" /><!--文字大小-->
</declare-styleable>
</resources>
3.2 重写onDraw()方法,开始画表格了
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/* 取平均高度和宽度 */
lineHeight = getHeight() / line;
columeWeight = getWidth() / column;
/* 用于画线的画笔 */
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
/* 设置线的宽度 */
paint.setStrokeWidth(1);
/* 用于写列表中数据的画笔 */
Paint paintText = new Paint();
paintText.setColor(Color.BLACK);
paintText.setStyle(Paint.Style.FILL);
paintText.setTextSize(textSize);
/* 获取字体信息 */
Paint.FontMetricsInt fontMetricsInt = paintText.getFontMetricsInt();
/* 文字为水平居中*/
paintText.setTextAlign(Paint.Align.CENTER);
/* 给第一行画上背景颜色 */
Paint paintTitles = new Paint();
paintTitles.setColor(0xffd3f0e0);
canvas.drawRect(new Rect(0, 0, columeWeight*column, lineHeight), paintTitles);
/* 给第一列画上背景颜色 */
Paint painFields = new Paint();
painFields.setColor(0xff9fd5b7);
canvas.drawRect(new Rect(0, lineHeight, columeWeight, lineHeight*line), painFields);
/* 开始画线 */
for(int i=0; i<line+1; i++){
/* 画水平线 */
canvas.drawLine(0, i*lineHeight, columeWeight*column, i*lineHeight, paint);
}
for(int i=0; i<column+1; i++){
/* 画竖直线 */
canvas.drawLine(i*columeWeight, 0, i*columeWeight, line*lineHeight, paint);
}
/* 填充文字 */
for(int j=0; j<line; j++) {
/* 写列的文字 */
for(int i=0; i<column; i++){
Rect targetRect = new Rect(i * columeWeight, j * lineHeight,
(i + 1) * columeWeight, (j + 1) * lineHeight);
/* 基线 =(目标区域中心点的y值-字体中心的y值) */
int baseline = (targetRect.bottom + targetRect.top - fontMetricsInt.bottom - fontMetricsInt.top) / 2;
if(j == 0){
/* 第一行显示标题 */
canvas.drawText(titles.get(i), targetRect.centerX(), baseline, paintText);
}else{
/* 第一列显示字段 */
if(i == 0){
canvas.drawText(fields.get(j-1), targetRect.centerX(), baseline, paintText);
}
/* 其他列显示字段值 */
else{
try {
String str = datas.get(fields.get(j-1)).get(i-1);
canvas.drawText((str == null)?"":str, targetRect.centerX(), baseline, paintText);
}catch (NullPointerException e){
e.printStackTrace();
}
}
}
}
}
}
3.3 在布局文件中引用
<com.richile.liu.formview.FormView
android:layout_width="match_parent"
android:layout_height="300dp"
formview:fields="@array/FormViewFields"
formview:titles="@array/FormViewTitles"
formview:textSize="12sp"/>
@array/FormViewFields和@array/FormViewTitles来源于文件form_titles_fields_array.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="FormViewTitles">
<item>姓名/学科</item>
<item>语文</item>
<item>数学</item>
<item>英语</item>
</string-array>
<string-array name="FormViewFields" >
<item>张三</item>
<item>李四</item>
<item>王五</item>
<item>王麻子</item>
</string-array>
</resources>
网友评论