Android绘图基本用法Demo

Android绘图是开发中比较常用的功能,虽然我用的少(层次不够^O^ ),对绘图的基本用法,适当记录一下。

Android绘图用到的两个重要的类是:
  • Paint.class(画笔)
  • Canvas.class (画布)
View绘图分三个重要步骤:
  1. Measure 测量
  2. Layout 布局
  3. Draw 绘制

知道了这些,就开始我们的demo吧。

Demo介绍:血糖含量在不同日期的变化折线图。

先上效果图:

这里写图片描述

XML布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@color/color_white">

    <android.support.v7.widget.CardView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_margin="10dp"
        card:cardBackgroundColor="@color/color_blue"
        card:cardCornerRadius="5dp"
        card:cardElevation="1dp"
        card:cardMaxElevation="1dp"
        >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_health_data_bloodsugar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:layout_marginTop="5dp"
                android:text="血糖    6.5mmol/L"
                android:textColor="@android:color/white"
                android:textSize="16sp"/>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:paddingLeft="10dp">

                <Button
                    android:id="@+id/btn_health_item_day"
                    style="@style/item_health_data_buttonStyle"
                    android:text="日"/>

                <Button
                    android:id="@+id/btn_health_item_week"
                    style="@style/item_health_data_buttonStyle"
                    android:text="周"/>

                <Button
                    android:id="@+id/btn_health_item_month"
                    style="@style/item_health_data_buttonStyle"
                    android:text="月"/>

                <Button
                    android:id="@+id/btn_health_item_year"
                    style="@style/item_health_data_buttonStyle"
                    android:text="年"
                    />
            </LinearLayout>

            <com.doctor.comonent.MyHealthDataView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginTop="5dp"
                />
        </LinearLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>
自定义绘制View
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;

import com.doctor.util.LogUtil;
import com.doctor.util.NumberUtil;

/**
 * Created by hgb
 * Date 2016/8/30 17:01.
 * Description : 自定义健康数据的view,用于用户健康数据的展示
 */
public class MyHealthDataView extends View {

    private Paint paint;        //画笔
    private int width;          //视图宽度
    private int height;         //视图的高度
    //坐标原点位置
    private int originX = 50;
    private int originY = 400;

    //画笔颜色
    private int paint_color_grey = Color.rgb(118, 188, 240);
    //表示最下面的日期.
    private String[] arrStr = new String[]{"19", "20", "21", "22", "23", "24", "25"};

    //对应日期不同的血糖值.空腹血糖正常范围是 3.9-6.1mmol/L(70-110mg/dL),正常餐后两小时血糖范围是 3.9-7.8mmol/L(70-140mg/dL)
    private Float[] arrFloat = new Float[]{1.9f, 5.4f, 6.1f, 4.0f, 5.5f, 2.5f, 4.8f};
    private float fSpace;         //水平方向x轴的间距.
    private int size;           //代表需要绘制的数据量
    private Float[] arrScale;   //点的高度占整体高度的比例

    public MyHealthDataView(Context context) {
        super(context);
        initPaint();
    }

    public MyHealthDataView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

    public MyHealthDataView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    /**
     * 开始进行绘制
     */
    public void setData() {
        postInvalidate();
    }

    /**
     * 初始化view
     */
    private void initPaint() {
        //创建画笔.
        paint = new Paint();
        paint.setColor(paint_color_grey);
        //设置画笔宽度
        paint.setStrokeWidth(3);
        //设置画笔抗锯齿
        paint.setAntiAlias(true);
    }

    /**
     * 测量
     *
     * @param widthMeasureSpec  宽
     * @param heightMeasureSpec 高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        LogUtil.e("width", width + "");

        height = MeasureSpec.getSize(heightMeasureSpec) - 60;
        LogUtil.e("height", height + "");
        // originX = 15;
        originY = height;
    }

    /**
     * 在ViewGroup位置中所处的位置
     *
     * @param changed 当前View的大小和位置改变了
     * @param left    左部位置(相对于父视图)
     * @param top     顶部位置(相对于父视图)
     * @param right   右部位置(相对于父视图)
     * @param bottom  底部位置(相对于父视图)
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    /**
     * 绘制
     *
     * @param canvas 画布
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制Y轴
        drawAxisY(canvas, paint);
        //绘制X轴坐标线(及下面的数据)
        drawAxisScaleMarkX(canvas, paint);
        //绘制水平的浅线
        drawHorizontalLine(canvas, paint);
        //绘制数据点,根据点连线
        drawPoint(canvas, paint);
        //根据点连线
        drawLine(canvas, paint);
    }

    /**
     * 绘制横坐标轴(X轴)
     */
    private void drawAxisX(Canvas canvas, Paint paint) {
        //画竖轴(Y)
        canvas.drawLine(originX, originY, originX, originY - height, paint);//参数说明:起始点左边x,y,终点坐标x,y,画笔
    }

    /**
     * 绘制纵坐标轴(Y轴)
     */
    private void drawAxisY(Canvas canvas, Paint paint) {
        //画横轴(X)
        canvas.drawLine(originX, originY, width - originX, originY, paint);
    }

    /**
     * 绘制X轴刻度线及下面的数据
     *
     * @param canvas
     * @param paint
     */
    private void drawAxisScaleMarkX(Canvas canvas, Paint paint) {
        paint.setTextSize(40);
        size = arrStr.length;  //文本数量
        int axisX = originX - 5;      //x轴距离,-5是为了让坐标点和数据对齐
        int axisY = originY + 40;              //Y轴坐标刻度值
        fSpace = ((float) width - 2 * originX) / (size - 1) - 3.0f;//Y轴数据之间的间距
        for (int i = 0; i < size; i++) {
            canvas.drawText(arrStr[i], axisX + fSpace * i, axisY, paint);
        }
    }

    /**
     * 绘制数据点
     *
     * @param canvas
     * @param paint
     */
    private void drawPoint(Canvas canvas, Paint paint) {
        //重写选取给paint赋值属性
        paint.setColor(Color.WHITE);       //设置画笔颜色
        paint.setStyle(Paint.Style.STROKE);  //设置画笔模式为描边
        paint.setStrokeWidth(10f);         //设置画笔宽度为10px

        arrScale = NumberUtil.getArrScale(arrFloat); //获取数组中每个值与最大值的比
        //绘制一组点,坐标位置由float数组指定
        for (int i = 0; i < size; i++) {
            canvas.drawPoint(originX + fSpace * i, (height - height * arrScale[i] + 10), paint);
        }
    }

    /**
     * 绘制水平横线
     *
     * @param canvas
     * @param paint
     */
    private void drawHorizontalLine(Canvas canvas, Paint paint) {
        int unit = -70;
        canvas.drawLines(new float[]{
                originX, originY + unit, width - originX, originY + unit,
                originX, originY + unit * 2, width - originX, originY + unit * 2,
                originX, originY + unit * 3, width - originX, originY + unit * 3,
                originX, originY + unit * 4, width - originX, originY + unit * 4,
                originX, originY + unit * 5, width - originX, originY + unit * 5
        }, paint);
    }

    /**
     * 根据点来连线
     *
     * @param canvas
     * @param paint
     */
    private void drawLine(Canvas canvas, Paint paint) {
        paint.setStrokeWidth(5f);         //设置画笔宽度为10px
        Path path = new Path();                     // 创建Path
        path.moveTo(originX, height - height * arrScale[0] + 10);                       // moveTo  把动作的起点移动到第一个点
        for (int i = 1; i < size; i++) {
            path.lineTo(originX + fSpace * i, height - height * arrScale[i] + 10);                      // lineTo 把剩下的点连接起来.
        }
        canvas.drawPath(path, paint);              // 绘制Path
    }
}

代码中用到的一个工具类NumberUtil

/**
 * Created by hgb
 * Date 2016/8/31 15:16.
 * Description : 处理数值的一些逻辑
 */
public class NumberUtil {
    /**
     * 获取一个float数组中的最大值
     *
     * @param arrFloat float类型数组
     * @return 返回数值中的最大值.
     */
    public static float getMaxNum(Float[] arrFloat) {
        int i;
        float max;
        int size = arrFloat.length;
        max = arrFloat[0];

        for (i = 0; i < size; i++) {
            if (arrFloat[i] > max)   // 判断最大值
                max = arrFloat[i];
        }
        return max;
    }

    /**
     * 获取数组中每个值与最大值的比
     *
     * @param arrFloat float类型数组
     * @return 比例
     */
    public static Float[] getArrScale(Float[] arrFloat) {
        float maxNum = getMaxNum(arrFloat);
        int i;
        int size = arrFloat.length;
        Float[] arrScale = new Float[size];
        for (i = 0; i < size; i++) {
            arrScale[i] = arrFloat[i] / maxNum;
        }
        return arrScale;
    }
}

这样,一个图表基本上就完成了。
Android中有很多复杂的绘图,paint和canvas的方法也多种多样,具体参见api详细文档。

Paint
Canvas
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值