自定义表格控件

2017-04-01  本文已影响0人  Richile
Paste_Image.png

一、背景
在做一些测试的时候经常会用到一些数据用于对比,或者显示多个字段在不同情况下的信息,这时用表格显示非常直观,所以就自定义了一个表格控件。

二、原理
绘制表格需要画直线,设置单元格的背景颜色,设置单元格中字体大小,设置单元格的高度,根据这些需求,我们可以使用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>
上一篇下一篇

猜你喜欢

热点阅读