Paste_Image.png
一、背景
在做一些測試的時候經(jīng)常會用到一些數(shù)據(jù)用于對比格郁,或者顯示多個字段在不同情況下的信息腹殿,這時用表格顯示非常直觀,所以就自定義了一個表格控件例书。
二锣尉、原理
繪制表格需要畫直線,設(shè)置單元格的背景顏色决采,設(shè)置單元格中字體大小自沧,設(shè)置單元格的高度,根據(jù)這些需求树瞭,我們可以使用View的onDraw()方法中的canvas快速實現(xiàn)拇厢,畫直線使用canvas.drawLine(),設(shè)置單元格背景顏色可以使用canvas.drawRect()和設(shè)置Paint對象的填充顏色移迫,設(shè)置字體大小可以使用canvas.drawText()和設(shè)置Paint對象的顏色旺嬉,設(shè)置單元格寬度和高度要設(shè)置兩條線起點之間的距離了。
三厨埋、實現(xiàn)
demo下載
3.1 繼承View,并且重寫3個View類的構(gòu)造方法捐顷,最主要的是帶3個參數(shù)的構(gòu)造方法
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);
}
/* 要增加一行用來顯示列標(biāo)題 */
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<>();
/* 第一列是用來顯示屬性的废赞,所以列表數(shù)據(jù)列數(shù)=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" /><!--顯示在第一行的標(biāo)題-->
<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);
/* 設(shè)置線的寬度 */
paint.setStrokeWidth(1);
/* 用于寫列表中數(shù)據(jù)的畫筆 */
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);
/* 基線 =(目標(biāo)區(qū)域中心點的y值-字體中心的y值) */
int baseline = (targetRect.bottom + targetRect.top - fontMetricsInt.bottom - fontMetricsInt.top) / 2;
if(j == 0){
/* 第一行顯示標(biāo)題 */
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>姓名/學(xué)科</item>
<item>語文</item>
<item>數(shù)學(xué)</item>
<item>英語</item>
</string-array>
<string-array name="FormViewFields" >
<item>張三</item>
<item>李四</item>
<item>王五</item>
<item>王麻子</item>
</string-array>
</resources>