Android自定义控件之美观的实用型统计表的制作

概述

绘制统计表,势必要用到自定义控件,一个统计表,看起来单元项很多,但实际上做起来并不复杂。
  • 要传递数据进来,用集合类最好。

  • 要确定每个表格单元的宽和高,并根据数据数目和表格每列的高来决定自定义控件的高。

  • 绘制表格线和表格单元背景的颜色,同时,绘制每个表格单元的文本。

先看看效果:

Demo

自定义一个控件:

/** * Created by Administrator on 2015/10/20. */
public class ChartTableView extends View {

    private int width;//控件宽
    private int height;//控件高
    private int dataNum;//数据量

    private Paint mPaintText;//用于绘制文本
    private Paint mPaintWhiteBg;//用于绘制白色背景
    private Paint mPaintGreyBg;//用于绘制灰色背景
    private Paint mPaintLightGrey;//用于绘制浅灰色背景
    private Paint mPaintLine;//用于画表格的列线

    private int visitSum;//总访问量
    private int workerSum;//员工总数目
    private float visitAverage;//平均访问量
    private int textSize = SizeConvert.dip2px(getContext(), 13);//文本尺寸,dp转px

    private ArrayList<VisitSummaryData> dataList;//总数据

    public ChartTableView(Context context) {
        super(context);
    }

    public ChartTableView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mPaintLine = new Paint();
        mPaintLine.setColor(Color.LTGRAY);
        mPaintLine.setStrokeWidth(1);
        mPaintLine.setAntiAlias(true);

        mPaintText = new Paint();
        mPaintText.setColor(Color.BLACK);
        mPaintText.setTextSize(textSize);
        mPaintText.setTextAlign(Paint.Align.CENTER);
        mPaintText.setAntiAlias(true);

        mPaintWhiteBg = new Paint();
        mPaintWhiteBg.setColor(Color.WHITE);
        mPaintWhiteBg.setStyle(Paint.Style.FILL);
        mPaintWhiteBg.setAntiAlias(true);


        mPaintGreyBg = new Paint();
        mPaintGreyBg.setColor(Color.argb(255, 240, 240, 240));
        mPaintGreyBg.setStyle(Paint.Style.FILL);
        mPaintGreyBg.setAntiAlias(true);

        mPaintLightGrey = new Paint();
        mPaintLightGrey.setColor(Color.argb(255, 250, 250, 250));
        mPaintLightGrey.setStyle(Paint.Style.FILL);
        mPaintLightGrey.setAntiAlias(true);

        dataList = new ArrayList<>();

    }

    /** * 得到dataList并确定一部分变量的值 * @param dataList */
    public void setDataList(ArrayList<VisitSummaryData> dataList) {
        this.dataList = dataList;
        dataNum = dataList.size();
        for(VisitSummaryData data:dataList){
            visitSum += data.getVisitTotal();
            workerSum += data.getWorkerTotal();
            visitAverage += data.getVisitDaily();
        }
        visitAverage /= dataNum;
        visitAverage = (float)(Math.round(visitAverage*10))/10;//让平均访问量只保留一位小数
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        //根据数据数量来得到控件高
        if (dataNum != 0) {
            height = (dataNum+1)*tableItemHeight;
        }
        //表格单元宽
        tableItemWidth = width/4;
        setMeasuredDimension(width, height);
    }

    private int tableItemWidth;
    private int tableItemHeight = SizeConvert.dip2px(getContext(),36);//表格单元高
    /** * 表格左上角的横纵坐标 */
    private float startX;
    private float startY;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制统计表表第一列
        canvas.drawRect(startX, startY, startX + tableItemWidth, startY + tableItemHeight, mPaintLightGrey);
        canvas.drawRect(startX + tableItemWidth, startY, width, startY + tableItemHeight, mPaintGreyBg);
        canvas.drawText("合计(" + dataNum + ")", startX + tableItemWidth / 2, startY + tableItemHeight / 2+textSize/2, mPaintText);
        canvas.drawText(visitSum+"",startX+tableItemWidth*3/2,startY+tableItemHeight/2+textSize/2,mPaintText);
        canvas.drawText(workerSum+"",startX+tableItemWidth*5/2,startY+tableItemHeight/2+textSize/2,mPaintText);
        canvas.drawText(visitAverage+"",startX+tableItemWidth*7/2,startY+tableItemHeight/2+textSize/2,mPaintText);

        for(int i=0;i<dataNum;i++){
            startY += tableItemHeight;
            canvas.drawRect(startX, startY, startX + tableItemWidth, startY + tableItemHeight, mPaintLightGrey);
            if(i%2==1) {
                canvas.drawRect(startX + tableItemWidth, startY, width, startY + tableItemHeight, mPaintGreyBg);
            }else {
                canvas.drawRect(startX + tableItemWidth, startY, width, startY + tableItemHeight, mPaintWhiteBg);
            }
            canvas.drawText(dataList.get(i).getName(), startX + tableItemWidth / 2, startY + tableItemHeight / 2+textSize/2, mPaintText);
            canvas.drawText(dataList.get(i).getVisitTotal()+"",startX+tableItemWidth*3/2,startY+tableItemHeight/2+textSize/2,mPaintText);
            canvas.drawText(dataList.get(i).getWorkerTotal()+"",startX+tableItemWidth*5/2,startY+tableItemHeight/2+textSize/2,mPaintText);
            canvas.drawText(dataList.get(i).getVisitDaily()+"",startX+tableItemWidth*7/2,startY+tableItemHeight/2+textSize/2,mPaintText);

            canvas.drawLine(0, tableItemHeight * (i + 1), width, tableItemHeight * (i + 1), mPaintLine);
        }

        startX=0;
        startY=0;

    }

尺寸转换工具类:

public class SizeConvert {

    /** * 将dp转换为sp */
    public static int dip2px(Context context, float dipValue){
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int)(dipValue * scale + 0.5f);
    }

    /** * sp转dp */
    public static int px2dip(Context context, float pxValue){
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int)(pxValue / scale + 0.5f);
    }
}

数据类,包含列表列单元的数据:

public class VisitSummaryData {
    private int id;
    private String name;
    private int visitTotal;
    private int workerTotal;
    private float visitDaily;

    public VisitSummaryData(int id, String name, int visitTotal, int workerTotal, float visitDaily) {
        this.id = id;
        this.name = name;
        this.visitTotal = visitTotal;
        this.workerTotal = workerTotal;
        this.visitDaily = visitDaily;
    }

    public VisitSummaryData(String name, int visitTotal, int workerTotal, float visitDaily) {
        this.name = name;
        this.visitTotal = visitTotal;
        this.workerTotal = workerTotal;
        this.visitDaily = visitDaily;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getVisitTotal() {
        return visitTotal;
    }

    public void setVisitTotal(int visitTotal) {
        this.visitTotal = visitTotal;
    }

    public int getWorkerTotal() {
        return workerTotal;
    }

    public void setWorkerTotal(int workerTotal) {
        this.workerTotal = workerTotal;
    }

    public float getVisitDaily() {
        return visitDaily;
    }

    public void setVisitDaily(int visitDaily) {
        this.visitDaily = visitDaily;
    }
}

主活动:

public class VisitSumTableActivity extends Activity {
    private ChartTableView chartTableView;
    private ArrayList<VisitSummaryData> dataList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_visit_summary);

        chartTableView = (ChartTableView) findViewById(R.id.chartTableView_visitSummary);
        initChartTable();
    }

    private void initChartTable() {
        dataList = new ArrayList<>();
        dataList.add(new VisitSummaryData("涛涛",23,35,3.5f));
        dataList.add(new VisitSummaryData("萌萌",22,42,2.5f));
        dataList.add(new VisitSummaryData("秀秀",14,24,5.5f));
        dataList.add(new VisitSummaryData("光光",66,347,3.0f));
        dataList.add(new VisitSummaryData("瑞瑞",42,34,3.9f));
        dataList.add(new VisitSummaryData("美美",24,44,0.5f));
        dataList.add(new VisitSummaryData("笑笑",24,77,2.3f));
        dataList.add(new VisitSummaryData("狒狒",87,69,9.8f));
        dataList.add(new VisitSummaryData("飞飞",97,45,3.2f));
        dataList.add(new VisitSummaryData("肥肥",69,38,4.5f));
        dataList.add(new VisitSummaryData("小明",28,68,7.5f));
        dataList.add(new VisitSummaryData("小红",27,34,9.5f));
        //将数据传入自定义控件里
        chartTableView.setDataList(dataList);
    }

}

布局文件layout_visit_summary.xml:这个布局文件并不是原布局文件,我删除了一些东西,可以根据自己的需要,自定义布局文件,只要声明了自定义控件并能显示在恰当位置就行了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">
    <RelativeLayout  android:id="@+id/relativeLayout_top" android:layout_width="match_parent" android:layout_height="60dp">

        <LinearLayout  android:id="@+id/linearlayout_backChart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="5dp" android:gravity="center" android:orientation="horizontal">
            <Button  android:layout_width="25dp" android:layout_height="25dp"/>

            <TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="报表"/>
        </LinearLayout>

        <TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="拜访汇总" android:textSize="20dp"/>

        <TextView  android:id="@+id/textView_ranking" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:text="排名" android:textSize="16dp"/>

    </RelativeLayout>
    <TextView  android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:text="昨日,快消体验版"/>
    <LinearLayout  android:layout_width="match_parent" android:layout_height="45dp" android:background="#818297">
        <TextView  android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:textSize="12dp" android:text="部门/人员"/>
        <TextView  android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="12dp" android:gravity="center" android:text="拜访总数"/>
        <TextView  android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:textSize="12dp" android:text="总工作人数"/>
        <TextView  android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:textSize="12dp" android:text="日人均拜访"/>
    </LinearLayout>
    <ScrollView  android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:scrollbars="none">
        <com.test.shiweiwei.myproject.widget.ChartTableView  android:id="@+id/chartTableView_visitSummary" android:layout_width="match_parent" android:layout_height="wrap_content"/>
    </ScrollView>

    <LinearLayout  android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" android:gravity="center">
        <RelativeLayout  android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingRight="10dp">
            <ImageButton  android:id="@+id/button_visitSum_refresh" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
            <TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/button_visitSum_refresh" android:padding="5dp" android:textSize="10dp" android:text="刷新"/>
        </RelativeLayout>

        <RelativeLayout  android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="20dp">
            <ImageButton  android:id="@+id/button_visitSum_sift" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
            <TextView  android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/button_visitSum_sift" android:padding="5dp" android:textSize="10dp" android:text="筛选"/>
        </RelativeLayout>
    </LinearLayout>

</LinearLayout>

程序员也需要有自己的乐趣,于是乎,我开通了音乐人账号,以后的作品将会上传到我的音乐人小站上。如果这篇博客帮助到您并且您也有时间,希望您能多关注,支持和推广,鼓励我将创作进行下去,先谢谢!

网易云音乐人,直接打开客户端搜索音乐人 “星河河”

豆瓣音乐人地址:https://site.douban.com/chuxinghe/ 星河河

你可能感兴趣的:(android,自定义控件,统计表)