博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android自定义View绘制天气温度曲线
阅读量:5962 次
发布时间:2019-06-19

本文共 11521 字,大约阅读时间需要 38 分钟。

原文:

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012942410/article/details/50091387

转载请注明出处:

大家好,不久前写了个绘制天气温度曲线功能的demo今天抽空来和大家分享一下。

效果图如下:

这里写图片描述

运用到我的项目效果图:

这里写图片描述

一般绘制图表,可以直接使用类库来实现,类似的类库还是很多的。

例如:

hellocharts-android

这里写图片描述

WilliamChart

这里写图片描述

MPAndroidChart

这里写图片描述

上述类库功能很多,可以实现很多种图表,效果也是非常绚丽的。

那么为什么这里我还要尝试自己绘制天气温度曲线呢,原因如下:

1.由于类库实现的功能比较多相对代码也稍显复杂,要想实现需求要改的地方还是挺多的,尝试的修改了几个类库代码,最终还是没能完全符合自己的需求,有的改后也莫名其妙的出现了细微的bug,不知道是不是修改的原因…因此也浪费了挺长的时间,不过也学到了很多的东西。

2.这么强大类库用来实现功能、效果相对单一的天气温度曲线是不是有点杀鸡焉用宰牛刀呢!

主要还是没能通过类库完全实现自己的需求,无奈逼迫自己走上了自定义View这条荆棘之路…

由于本人接触安卓时间并不算长,还没有自定义过组件,所以对于自定义View还是比较畏惧的…

经过方案的思考与整理,发现自定义View来实现天气温度曲线并没有想象中的那么难,相反还是挺简单的,而且代码量也是相当的少,只需要覆写View类的 onDraw(Canvas canvas) 方法即可实现需求。

自定义View代码如下:

/* * Copyright (c) 2016 Kaku咖枯 
* * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package com.kaku.wcv;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.DashPathEffect;import android.graphics.Paint;import android.graphics.Path;import android.util.AttributeSet;import android.view.View;import com.kaku.library.R;// The plan//*-----------------------------------------*// SPACE *//*-----------------------------------------*// TEXT *//*-----------------------------------------*// TEXT SPACE *//*-----------------------------------------*// RADIUS *//*-----------------------------------------*// | *// | *// | *// ---------(x,y)-------- *// | *// | *// | *//*-----------------------------------------*// RADIUS *//*-----------------------------------------*// TEXT SPACE *//*-----------------------------------------*// TEXT *//*-----------------------------------------*// SPACE *//*-----------------------------------------*/** * 折线温度双曲线 * * @author 咖枯 * @version 1.0 2015/11/06 */public class WeatherChartView extends View {
/** * x轴集合 */ private float mXAxis[] = new float[6]; /** * 白天y轴集合 */ private float mYAxisDay[] = new float[6]; /** * 夜间y轴集合 */ private float mYAxisNight[] = new float[6]; /** * x,y轴集合数 */ private static final int LENGTH = 6; /** * 白天温度集合 */ private int mTempDay[] = new int[6]; /** * 夜间温度集合 */ private int mTempNight[] = new int[6]; /** * 控件高 */ private int mHeight; /** * 字体大小 */ private float mTextSize; /** * 圓半径 */ private float mRadius; /** * 圓半径今天 */ private float mRadiusToday; /** * 文字移动位置距离 */ private float mTextSpace; /** * 线的大小 */ private float mStokeWidth; /** * 白天折线颜色 */ private int mColorDay; /** * 夜间折线颜色 */ private int mColorNight; /** * 字体颜色 */ private int mTextColor; /** * 屏幕密度 */ private float mDensity; /** * 控件边的空白空间 */ private float mSpace; @SuppressWarnings("deprecation") public WeatherChartView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WeatherChartView); float densityText = getResources().getDisplayMetrics().scaledDensity; mTextSize = a.getDimensionPixelSize(R.styleable.WeatherChartView_textSize, (int) (14 * densityText)); mColorDay = a.getColor(R.styleable.WeatherChartView_dayColor, getResources().getColor(R.color.colorAccent)); mColorNight = a.getColor(R.styleable.WeatherChartView_nightColor, getResources().getColor(R.color.colorPrimary)); mTextColor = a.getColor(R.styleable.WeatherChartView_textColor, Color.WHITE); a.recycle(); mDensity = getResources().getDisplayMetrics().density; mRadius = 3 * mDensity; mRadiusToday = 5 * mDensity; mSpace = 3 * mDensity; mTextSpace = 10 * mDensity; mStokeWidth = 2 * mDensity; } public WeatherChartView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mHeight == 0) { // 设置控件高度,x轴集合 setHeightAndXAxis(); } // 计算y轴集合数值 computeYAxisValues(); // 画白天折线图 drawChart(canvas, mColorDay, mTempDay, mYAxisDay, 0); // 画夜间折线图 drawChart(canvas, mColorNight, mTempNight, mYAxisNight, 1); } /** * 计算y轴集合数值 */ private void computeYAxisValues() { // 存放白天最低温度 int minTempDay = mTempDay[0]; // 存放白天最高温度 int maxTempDay = mTempDay[0]; for (int item : mTempDay) { if (item < minTempDay) { minTempDay = item; } if (item > maxTempDay) { maxTempDay = item; } } // 存放夜间最低温度 int minTempNight = mTempNight[0]; // 存放夜间最高温度 int maxTempNight = mTempNight[0]; for (int item : mTempNight) { if (item < minTempNight) { minTempNight = item; } if (item > maxTempNight) { maxTempNight = item; } } // 白天,夜间中的最低温度 int minTemp = minTempNight < minTempDay ? minTempNight : minTempDay; // 白天,夜间中的最高温度 int maxTemp = maxTempDay > maxTempNight ? maxTempDay : maxTempNight; // 份数(白天,夜间综合温差) float parts = maxTemp - minTemp; // y轴一端到控件一端的距离 float length = mSpace + mTextSize + mTextSpace + mRadius; // y轴高度 float yAxisHeight = mHeight - length * 2; // 当温度都相同时(被除数不能为0) if (parts == 0) { for (int i = 0; i < LENGTH; i++) { mYAxisDay[i] = yAxisHeight / 2 + length; mYAxisNight[i] = yAxisHeight / 2 + length; } } else { float partValue = yAxisHeight / parts; for (int i = 0; i < LENGTH; i++) { mYAxisDay[i] = mHeight - partValue * (mTempDay[i] - minTemp) - length; mYAxisNight[i] = mHeight - partValue * (mTempNight[i] - minTemp) - length; } } } /** * 画折线图 * * @param canvas 画布 * @param color 画图颜色 * @param temp 温度集合 * @param yAxis y轴集合 * @param type 折线种类:0,白天;1,夜间 */ private void drawChart(Canvas canvas, int color, int temp[], float[] yAxis, int type) { // 线画笔 Paint linePaint = new Paint(); // 抗锯齿 linePaint.setAntiAlias(true); // 线宽 linePaint.setStrokeWidth(mStokeWidth); linePaint.setColor(color); // 空心 linePaint.setStyle(Paint.Style.STROKE); // 点画笔 Paint pointPaint = new Paint(); pointPaint.setAntiAlias(true); pointPaint.setColor(color); // 字体画笔 Paint textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setColor(mTextColor); textPaint.setTextSize(mTextSize); // 文字居中 textPaint.setTextAlign(Paint.Align.CENTER); int alpha1 = 102; int alpha2 = 255; for (int i = 0; i < LENGTH; i++) { // 画线 if (i < LENGTH - 1) { // 昨天 if (i == 0) { linePaint.setAlpha(alpha1); // 设置虚线效果 linePaint.setPathEffect(new DashPathEffect(new float[]{
2 * mDensity, 2 * mDensity}, 0)); // 路径 Path path = new Path(); // 路径起点 path.moveTo(mXAxis[i], yAxis[i]); // 路径连接到 path.lineTo(mXAxis[i + 1], yAxis[i + 1]); canvas.drawPath(path, linePaint); } else { linePaint.setAlpha(alpha2); linePaint.setPathEffect(null); canvas.drawLine(mXAxis[i], yAxis[i], mXAxis[i + 1], yAxis[i + 1], linePaint); } } // 画点 if (i != 1) { // 昨天 if (i == 0) { pointPaint.setAlpha(alpha1); canvas.drawCircle(mXAxis[i], yAxis[i], mRadius, pointPaint); } else { pointPaint.setAlpha(alpha2); canvas.drawCircle(mXAxis[i], yAxis[i], mRadius, pointPaint); } // 今天 } else { pointPaint.setAlpha(alpha2); canvas.drawCircle(mXAxis[i], yAxis[i], mRadiusToday, pointPaint); } // 画字 // 昨天 if (i == 0) { textPaint.setAlpha(alpha1); drawText(canvas, textPaint, i, temp, yAxis, type); } else { textPaint.setAlpha(alpha2); drawText(canvas, textPaint, i, temp, yAxis, type); } } } /** * 绘制文字 * * @param canvas 画布 * @param textPaint 画笔 * @param i 索引 * @param temp 温度集合 * @param yAxis y轴集合 * @param type 折线种类:0,白天;1,夜间 */ private void drawText(Canvas canvas, Paint textPaint, int i, int[] temp, float[] yAxis, int type) { switch (type) { case 0: // 显示白天气温 canvas.drawText(temp[i] + "°", mXAxis[i], yAxis[i] - mRadius - mTextSpace, textPaint); break; case 1: // 显示夜间气温 canvas.drawText(temp[i] + "°", mXAxis[i], yAxis[i] + mTextSpace + mTextSize, textPaint); break; } } /** * 设置高度,x轴集合 */ private void setHeightAndXAxis() { mHeight = getHeight(); // 控件宽 int width = getWidth(); // 每一份宽 float w = width / 12; mXAxis[0] = w; mXAxis[1] = w * 3; mXAxis[2] = w * 5; mXAxis[3] = w * 7; mXAxis[4] = w * 9; mXAxis[5] = w * 11; } /** * 设置白天温度 * * @param tempDay 温度数组集合 */ public void setTempDay(int[] tempDay) { mTempDay = tempDay; } /** * 设置夜间温度 * * @param tempNight 温度数组集合 */ public void setTempNight(int[] tempNight) { mTempNight = tempNight; }}

布局文件中只需引入上面自定义的View即可:

Activity中动态设置白天夜间温度集合数值:

WeatherChartView chartView = (WeatherChartView) findViewById(R.id.line_char);        // 设置白天温度曲线            chartView .setTempDay(new int[]{tempDay1,tempDay2,tempDay3,tempDay4,tempDay5,tempDay6});        // 设置夜间温度曲线            chartView .setTempNight(new int[]{tempNight1,tempNight2,tempNight3,tempNight4,tempNight5,tempNight6});                      chartView .invalidate();

好了,到这里大功告成,是不是觉得还是很简单的吧。

写的不好的地方希望大家指出,谢谢!

Github地址

你可能感兴趣的文章
NYOJ-取石子
查看>>
AngularJS
查看>>
《zw版·Halcon-delphi系列原创教程》halconxlib控件列表
查看>>
List与数组的相互转换
查看>>
Computer Science Theory for the Information Age-4: 一些机器学习算法的简介
查看>>
socketserver模块使用方法
查看>>
json模块
查看>>
各型号英特尔CUP的功率
查看>>
scanf()中的%c 不能正常输入的问题
查看>>
常见排序算法及对应的时间复杂度和空间复杂度
查看>>
业界 | 在德州叫一辆自动驾驶车,Drive.ai安排了7辆无人车展开真实试验
查看>>
实时数据平台设计:解决从OLTP到OLAP实时流转缺失
查看>>
三家公司在SD-WAN方面的新动作
查看>>
C#在PDF中如何以不同颜色高亮文本
查看>>
在同一页面显示多个JavaScript统计图表
查看>>
Mac电脑Tomcat下载及安装(详细)MAC在Eclipse里配置tomcat
查看>>
多线程之-----------定时器
查看>>
C#语法——反射,架构师的入门基础。
查看>>
Beego Models 之 一
查看>>
代码生成工具Database2Sharp中增加视图的代码生成以及主从表界面生成功能
查看>>