自定义view,天气折线图

作者: zhongjh | 来源:发表于2018-04-20 18:05 被阅读243次

公司能用到自定义view的不多,有个简单的折线图练手,花了大半天时间基本搞定,嗯,代码放这了。

image.png

放代码前先放我平时学习做的一些记录
Path.addCircle
canvas
Point
Rect类和RectF类
Paint类
onMeasure

代码放这,核心注释已经写的很清楚了。时间关系,一些简单方法的注释我后面再补充。

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;

import xzh.com.mojiweather.R;
import xzh.com.mojiweather.model.ChartItem;
import xzh.com.mojiweather.utils.Utils;

/**
 * 绘制天气折线图的View
 */
public class ChartView extends View {

    // 上下文
    private Context context;
    // 早上数据源
    private ArrayList<ChartItem> items;
    // 晚上数据源
    private ArrayList<ChartItem> items2;
    // 早上的x坐标数据源
    ArrayList<Integer> xlist;
    // 晚上的x坐标数据源
    ArrayList<Integer> xlist2;
    // 提示文字
    private String unit;
    // 格式化
    private String yFormat = "0.#°";

    int mSplit;
    // 顶部间距
    int mYMargintTop;
    int mMargint2;

    // 线条的油漆
    Paint mPaint;
    // 单位文字的油漆
    Paint mPaintUnit;

    /**
     * 赋值
     *
     * @param list     数据源
     * @param unitInfo 提示文字
     */
    public void setView(ArrayList<ChartItem> list, ArrayList<ChartItem> list2, String unitInfo) {
        this.items = list;
        this.items2 = list2;
        this.unit = unitInfo;
    }

    public ChartView(Context ct) {
        super(ct);
        this.context = ct;
        init();
    }

    public ChartView(Context ct, AttributeSet attrs) {
        super(ct, attrs);
        this.context = ct;
        init();
    }

    public ChartView(Context ct, AttributeSet attrs, int defStyle) {
        super(ct, attrs, defStyle);
        this.context = ct;
        init();
    }

    /**
     * 初始化工具
     */
    private void init() {
        // 初始化所有单位
        mSplit = Utils.dip2px(context, 20);
        mYMargintTop = Utils.dip2px(context, 60);
        mMargint2 = Utils.dip2px(context, 25);

        // x坐标的数据源
        xlist = new ArrayList<>();
        xlist2 = new ArrayList<>();

        // 初始化 油漆
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(context.getResources().getColor(R.color.weather_line));
        mPaint.setStrokeWidth(4);
        mPaint.setStyle(Paint.Style.STROKE);

        // 初始化单位 的油漆
        mPaintUnit = new Paint();
        mPaintUnit.setTextSize(Utils.sp2px(context, 12));
        mPaintUnit.setColor(context.getResources().getColor(R.color.weather_line));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (items == null || items2 == null) {
            return;
        }

        int height = getHeight();
        int width = getWidth();
        // 左右间距
        int marginl = 0;
        int bheight = height - mYMargintTop - 2 * mSplit;

        // 画单位
//        canvas.drawText(unit, mSplit + Utils.dip2px(context, 30f), mMargint2 + mSplit * 2, mPaintUnit);

        // 画早上的X坐标值
        mPaint.setColor(Color.GRAY);
        mPaint.setTextSize(15);//设置字体大小
        for (int i = 0; i < items.size(); i++) {
            // 获取跨度,比如3条数据就平均3块
            int span = (width - 2 * marginl) / items.size();
            // 算出每个跨度的中间值,该值就是x了
            int x = marginl + span / 2 + span * i;
            xlist.add(x);
            drawText(items.get(i).getX(), x, mSplit * 2, canvas);
        }
        // 画晚上的X坐标值
        for (int i = 0; i < items2.size(); i++) {
            // 获取跨度,比如3条数据就平均3块
            int span = (width - 2 * marginl) / items2.size();
            // 算出每个跨度的中间值,该值就是x了
            int x = marginl + span / 2 + span * i;
            xlist2.add(x);
            drawText(items2.get(i).getX(), x, mSplit * 2, canvas);
        }

        // 获取最大值和最小值
        float max = Float.MIN_VALUE;
        float min = Float.MAX_VALUE;
        for (int i = 0; i < items.size(); i++) {
            float y = items.get(i).getY();
            if (y > max) {
                max = y;
            }
            if (y < min) {
                min = y;
            }
        }
        for (int i = 0; i < items2.size(); i++) {
            float y = items2.get(i).getY();
            if (y > max) {
                max = y;
            }
            if (y < min) {
                min = y;
            }
        }

        // 最大跟最小的差距为0,则设置默认值6给它们
        float span = max - min;
        if (span == 0) {
            span = 6.0f;
        }
        // 添加差距,这样即使span为6,最大的也+1,最小的也-1。他们相差就2点了
        max = max + span / 6.0f;
        min = min - span / 6.0f;

        // 获取点集合
        Point[] mPoints = getPoints(items, xlist, max, min, bheight, mYMargintTop);
        Point[] mPoints2 = getPoints(items2, xlist2, max, min, bheight, mYMargintTop);

        // 画线
        mPaint.setColor(context.getResources().getColor(R.color.morning_color));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(8);
        drawLine(mPoints, canvas, mPaint);
        mPaint.setColor(context.getResources().getColor(R.color.night_color));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(8);
        drawLine(mPoints2, canvas, mPaint);

        // 画点
        mPaint.setColor(context.getResources().getColor(R.color.morning_color));
        mPaint.setStyle(Paint.Style.FILL);
        for (int i = 0; i < mPoints.length; i++) {
            canvas.drawCircle(mPoints[i].x, mPoints[i].y, 12, mPaint);
            @SuppressLint("DrawAllocation")
            String yText = new java.text.DecimalFormat(yFormat).format(items.get(i).getY());
            drawText(yText, mPoints[i].x,
                    mPoints[i].y - Utils.dip2px(context, 12), canvas);
        }
        mPaint.setColor(context.getResources().getColor(R.color.night_color));
        for (int i = 0; i < mPoints2.length; i++) {
            canvas.drawCircle(mPoints2[i].x, mPoints2[i].y, 12, mPaint);
            @SuppressLint("DrawAllocation")
            String yText = new java.text.DecimalFormat(yFormat).format(items2.get(i).getY());
            drawText(yText, mPoints2[i].x,
                    mPoints2[i].y - Utils.dip2px(context, 12), canvas);
        }
    }

    /**
     * @param items items数据源
     * @param xlist 横轴坐标
     * @param max   最大的max
     * @param min   最小的min
     * @param h     仅仅该折现图的高度
     * @param top   顶部间距
     * @return Point
     */
    private Point[] getPoints(ArrayList<ChartItem> items, ArrayList<Integer> xlist, float max, float min,
                              int h, int top) {
        // 实例化point
        Point[] points = new Point[items.size()];
        // 获取y轴位置,这个逻辑还是很好理解的
        for (int i = 0; i < items.size(); i++) {
            // (1)items.get(i).getY() - min 首先是y的实际天气度数数据 - 最小的y轴数据获取他们的差距作为分子
            double molecule = items.get(i).getY() - min;
            // (2)max - min 获取y轴的范围作为分母
            double denominator = max - min;
            // (3)然后是h具体高度*(1)(2)步骤组成的分子分母获取 具体的 y轴差异 数据
            int yDifference = (int) (h * (molecule / denominator));
            //  (4)最后 h+顶部间距 - y轴差异 就获得y轴数据了
            int y = top + h - yDifference;
            points[i] = new Point(xlist.get(i), y);
        }
        return points;
    }

    private void drawLine(Point[] ps, Canvas canvas, Paint paint) {
        Point startp;
        Point endp;
        for (int i = 0; i < ps.length - 1; i++) {
            startp = ps[i];
            endp = ps[i + 1];
            canvas.drawLine(startp.x, startp.y, endp.x, endp.y, paint);
        }
    }

    private void drawText(String text, int x, int y, Canvas canvas) {
        Paint p = new Paint();
        p.setAlpha(context.getResources().getColor(R.color.color_write));
        p.setTextSize(Utils.sp2px(context, 14));
        p.setTextAlign(Paint.Align.CENTER);
        p.setColor(Color.WHITE);
        canvas.drawText(text, x, y, p);
    }


}

相关文章

  • 自定义view,天气折线图

    公司能用到自定义view的不多,有个简单的折线图练手,花了大半天时间基本搞定,嗯,代码放这了。 放代码前先放我平时...

  • 自定义View集合

    自定义View集合 一、 折线图 开源库推荐 WilliamChart MPAndroidChart 效果图样式效...

  • 自定义View-天气预报折线图(一)

    前段时间自己做的天气预报小demo挂掉了,因此想要重新做一个 之前的天气预报没有加入折线图 自定义View还只是刚...

  • Android自定义View练习--折线图

    本练习参考 自定义View练习(二)简易折线图控件,折线图支持设置x轴与y轴的取值范围与递增值,效果如下: 首先自...

  • iOS开发波浪线图

    波浪线图等同于折线图, 只是添加了填充, 另外实现波浪的效果.实现同样自定义封装了view, 在UIBezierP...

  • 柱状图-折线图-饼状图

    下午自己闲着没事,写了一个自定义的柱状图,折线图,以及饼状图把我自定义的view代码粘贴上来传送门:https:/...

  • 自定义view - 折线图

    自定义 view 在 Android 开发中会经常用到,本项目是一个很好的学习例子,如果有空可以看一下哟! 来看下...

  • Android View(转)

    自定义View的原理自定义View基础 - 最易懂的自定义View原理系列自定义View Measure过程 - ...

  • 自定义View系列

    自定义View1---知识储备自定义View2---View Measure过程自定义View3---View L...

  • 自定义View5---完整的自定义View

    移步自定义View系列 1.自定义view的分类自定义单一view(不含子view)继承view继承特定view如...

网友评论

    本文标题:自定义view,天气折线图

    本文链接:https://www.haomeiwen.com/subject/hiezkftx.html