Android自定义View实现天气预报折线图
作者:xiao芝麻 发布时间:2023-08-22 14:37:50
标签:Android,View,折线图
本文实例为大家分享了Android自定义View画天气预报折线图的具体代码,供大家参考,具体内容如下
效果图如下:
刚开始尝试用第三方画曲线的框架来画效果图,后来发现曲线间的阴影当有负数的度数的时候画不出来,而且不需要点击放大、点点可点的效果,用框架显得很臃肿,所以最后用自定义View来画的折线图。自定义画折线图的大致思路:这个图是有多个四边形组成的(4个点连接起来就是一个四边形),两边延伸:添加四个多余的点,将左右的边距设置成负数即可。
代码如下:
public class WeatherChartView extends View {
/**
* x轴集合
*/
private float mXAxis[] ;
/**
* 白天y轴集合
*/
private float mYAxisDay[] ;
/**
* 夜间y轴集合
*/
private float mYAxisNight[] ;
/**
* x,y轴集合数
*/
private int LENGTH ;
/**
* 白天温度集合
*/
private int mTempDay[] ;
/**
* 夜间温度集合
*/
private int mTempNight[] ;
/**
* 控件高
*/
private int mHeight;
/**
* 字体大小
*/
private float mTextSize;
/**
* 圓半径
*/
private float mRadius ;
/**
* 圓半径今天
*/
private float mRadiusToday ;
/**
* 文字移动位置距离
*/
private float mTextSpace ;
/**
* 线的大小
*/
private float mStokeWidth ;
/**
* 白天折线颜色
*/
private int mColorDay = Color.parseColor("#ffffff");
/**
* 夜间折线颜色
*/
private int mColorNight = Color.parseColor("#ffffff");;
/**
* 字体颜色
*/
private int mTextColor = Color.parseColor("#ffffff");;
/**
* 屏幕密度
*/
private float mDensity;
/**
* 控件边的空白空间
*/
private float mSpace;
@SuppressWarnings("deprecation")
public WeatherChartView(Context context, AttributeSet attrs) {
super(context, attrs);
mDensity = getResources().getDisplayMetrics().density;
mRadius = 3 * mDensity;
mRadiusToday = 3 * mDensity;
//mSpace = 3 * mDensity;
mTextSpace = 10 * mDensity;
mStokeWidth = 2 * mDensity;
mTextSize = BreakRuleTools.dip2px(context, 12);
}
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) {
color = Color.parseColor("#ffffff");
// 线画笔
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 == -1) {
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 {
if(type == 0) {
linePaint.setAlpha(76);
linePaint.setPathEffect(null);
linePaint.setStyle(Paint.Style.FILL);//设置实心
Path path = new Path(); //Path对象
path.moveTo(mXAxis[i], mYAxisDay[i]); //起始点
path.lineTo(mXAxis[i + 1], mYAxisDay[i + 1]); //连线到下一点
path.lineTo(mXAxis[i + 1], mYAxisNight[i + 1]); //连线到下一点
path.lineTo(mXAxis[i], mYAxisNight[i]); //连线到下一点
path.lineTo(mXAxis[i], mYAxisDay[i]); //连线到下一点
canvas.drawPath(path, linePaint); //绘制任意多边形
}
//canvas.drawLine(mXAxis[i], yAxis[i], mXAxis[i + 1], yAxis[i + 1], linePaint);
}
}
// 画点
if (i != 1) {
// 昨天
if (i == 0 || i == LENGTH - 1) {
/*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 || i == LENGTH - 1) {
/*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();
int i = LENGTH - 2;
// 每一份宽
float w = width / (i*2);
for(int j =0;j<LENGTH;j++){
if(j == 0){
mXAxis[j] = 0;
} else if(j == LENGTH -1){
mXAxis[j] = width;
} else{
mXAxis[j] = w * (2*j -1);
}
}
/* mXAxis[0] = 0;
mXAxis[1] = w;
mXAxis[2] = w * 3;
mXAxis[3] = w * 5;
mXAxis[4] = w * 7;
mXAxis[5] = w * 9;
mXAxis[6] = width;*/
/* mXAxis[5] = w * 11;
mXAxis[6] = w * 13;*/
}
/**
* 设置白天温度
*
* @param tempDay 温度数组集合
*/
public void setTempDay(int[] tempDay) {
mTempDay = tempDay;
LENGTH = mTempDay.length;
mXAxis = new float[LENGTH];
mYAxisDay = new float[LENGTH];
mYAxisNight = new float[LENGTH];
/*mTempDay = new int[LENGTH];
mTempNight = new int[LENGTH];*/
}
/**
* 设置夜间温度
*
* @param tempNight 温度数组集合
*/
public void setTempNight(int[] tempNight) {
mTempNight = tempNight;
}
/**
* 设置白天曲线的颜色
*/
public void setColorDay(){}
}
布局代码:
<com.pingan.carowner.weather.view.WeatherChartView
android:id="@+id/line_char"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_below="@id/weather_over_view_item3"
android:layout_centerInParent="true"/>
代码引用:
// 设置白天温度曲线
mChartView = (WeatherChartView) findViewById(R.id.line_char);
mChartView.setTempDay(highTemp);//highTemp 高温度集合
// 设置夜间温度曲线
mChartView.setTempNight(lowTemp);//lowTemp 低温集合
mChartView.invalidate();
来源:https://blog.csdn.net/u013704970/article/details/53738534


猜你喜欢
- 建造者模式概述建造者模式(Builder Pattern)属于创建型模式。它是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同
- 1.情景展示静态方法内部实现:将指定内容生成图片格式的二维码;如何通过多线程实现?2.分析之所以采用多线程,是为了节省时间 3.解
- 1.实现一个ItsClient 客户端用来实例化调用验证功能public class ItsClient {private static f
- 在日常系统开发中,经常需要在adroid的framework修改或添加自己的配置。例如在config.xml 添加一个新的变量。我这边测试发
- 前言工作中是否有这样的场景,多个线程任务,如果所有线程完成到某个阶段,你希望知道所有线程均完成该阶段。当然你使用线程计数可以实现,只是不够优
- 在Java中我们知道静态变量会在类加载时机的“初始化”阶段得到赋值(编译器会收集类中的静态变量及静态
- 将Object类转换为实体类问题描述在用SpringBoot写controller的时候,需要接受一个map的Object,之后要把Obje
- 安卓开发网络请求可谓是安卓开发的灵魂,如果你不会网络请求,那么你开发的应用软件就是一具没有灵魂的枯骨。在安卓开发中进行网络请求和java中的
- eclipse汉化包我们会经常用到,因为它可以帮助英语基础差的用户更快的掌握这个软件,非常方便,但是我看了下整个互联网上并没有对这个汉化包进
- 概述在本文章中,我们对如何在 Java 中对 Array 和 List 进行转换进行一些说明和示例。这些示例通过使用 Core Java 和
- IDEA修改idea64.exe.vmoptions文件及解决coding卡顿用idea软件同时打开多个项目时,过个几天不关闭,就慢慢陷入卡
- SpringMVC * 介绍springMVC 中的 * 用于拦截控制器方法的执行。先创建出前置需要的一些条件:<a th:href=
- 并发编程中的三个概念:1.原子性在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执
- 本文实例为大家分享了C#使用NPOI将excel导入到list的具体代码,供大家参考,具体内容如下这个是确定是实体类接收/// <su
- 水流波动的波形都是三角波,曲线是正余弦曲线,但是Android中没有提供绘制正余弦曲线的API,好在Pa
- Java doGet, doPost方法和文件上传index.html<!DOCTYPE html><html lang=
- 本文实例为大家分享了java实现webservice方式的具体代码,供大家参考,具体内容如下经过测试 jdk1.6.10以下会出现bug 建
- 免责声明:本教程所有资源均来源于网络;仅用于学习交流,请勿用于任何商业行为;如需要,请使用正版授权;侵权联删。推荐最新 IntelliJ I
- 需要添加对 System.Management.dll 的引用 using System.Diagnostics; using System
- centos下搭建GitLab+Jenkins持续集成环境,供大家参考,具体内容如下1、安装JDKyum install -y java2、