Android 曲线覆盖图

看图

 

样例代码

layout.xml

<com.XXXXX.utils.GraphBendLineandroid:id="@+id/ghost_view"android:layout_width="200dp"android:layout_height="200dp"android:layout_margin="40dp"app:node_bar_line_color="#F9FEFD"app:node_bar_line_dan_color="#BAEFE6"app:node_color="#D7F5F0"app:node_line_color="#8BE4D4" />

attr.xml

<declare-styleable name="nodeLine"><!--节点默认颜色--><attr name="node_color" format="color" /><!--曲线颜色--><attr name="node_bar_line_color" format="color" /><!--曲线颜色浅色--><attr name="node_bar_line_dan_color" format="color" /><!--进度条默认颜色--><attr name="node_line_color" format="color" /></declare-styleable>

activity

GraphBendLine mLine = (GraphBendLine) findViewById(R.id.ghost_view);timeList.add(80f);
timeList.add(0f);
timeList.add(50f);
timeList.add(20f);
timeList.add(60f);
timeList.add(20f);
timeList.add(90f);
dataList.add("3.15");
dataList.add("3.16");
dataList.add("3.17");
dataList.add("3.18");
dataList.add("3.19");
dataList.add("3.20");
dataList.add("3.21");
mLine.updateTime(timeList, dataList);

画布类

public class GraphBendLine extends View {private float sumHeight;//总控件的高度private float sumWidth;//总空间的宽度private float maxY;//y轴最大值private float minY;//y轴最小值private float centerY;//y轴中间值private String unitY;//y轴值单位private float maxTime;//最大的时间 用来划分单位的 最小就是20 X1.2是为了给上方和下方预留空间private Paint linePaint;//线的画笔private Paint shadowPaint;//阴影的画笔private Paint mPaint;//曲线画笔private Paint circlePaint;//圆点画笔private Paint circlePaint2;//圆点画笔private Paint scorePaint;private Paint textPaint;//文字的画笔private ArrayList<Float> dataList;//监测值private ArrayList<String> timeList;//底部的时间private float oneHeight; //每一个小段所要分成的高private float oneWidth;//每一个小段所要分成的宽private float buttomHeiht; //给底部一排日期预留出的时间private Path baseLinePath;//折线路径private float smoothness = 0.36f; //折线的弯曲率private Paint baseShadow;//折线下的阴影的画笔private String lineColor = "#CBF2ED";//节点默认颜色 "#17CAAA"private String barLineColor = "#BAEFE6";//曲线覆盖区颜色private String barLineDanColor = "#D7F5F0";//曲线覆盖区浅颜色颜色  "#F9FEFD"private String nodeColor = "#8BE4D4";//节点默认颜色private ArrayList<PointF> xyList;//储存定好的坐标点的集合public GraphBendLine(Context context) {super(context);initPaint();}public GraphBendLine(Context context, AttributeSet attrs) {super(context, attrs);//        mContext = context;TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.nodeLine);lineColor = ta.getString(R.styleable.nodeLine_node_line_color);nodeColor = ta.getString(R.styleable.nodeLine_node_color);barLineColor = ta.getString(R.styleable.nodeLine_node_bar_line_color);barLineDanColor = ta.getString(R.styleable.nodeLine_node_bar_line_dan_color);ta.recycle();initPaint();}/*** 初始化画笔** @linpaint 线条画笔* @shadowPaint 阴影画笔*/private void initPaint() {//画线的画笔linePaint = new Paint();linePaint.setColor(Color.parseColor("#333333"));linePaint.setAntiAlias(true);linePaint.setTextSize(dp2px(getContext(), 9));linePaint.setStrokeWidth(dp2px(getContext(), 1));//画背景的画笔shadowPaint = new Paint();shadowPaint.setColor(Color.parseColor(lineColor));shadowPaint.setAntiAlias(true);//画最下方文字的画笔textPaint = new Paint();textPaint.setColor(Color.parseColor("#333333"));textPaint.setAntiAlias(true);textPaint.setTextSize(dp2px(getContext(), 8));circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);circlePaint.setColor(Color.WHITE);circlePaint.setStrokeWidth(dp2px(getContext(), 2));circlePaint.setStyle(Paint.Style.STROKE);circlePaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);circlePaint2.setColor(Color.parseColor(lineColor));circlePaint2.setStyle(Paint.Style.FILL);baseShadow = new Paint();baseShadow.setAntiAlias(true);baseShadow.setColor((Color.WHITE & 0x40FFFFFF) | 0x10000000);baseShadow.setStyle(Paint.Style.FILL);buttomHeiht = dp2px(35);//线距离底部高度mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(Color.parseColor(lineColor));mPaint.setStrokeWidth(dp2px(getContext(), 2));mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeCap(Paint.Cap.ROUND);scorePaint = new Paint(Paint.ANTI_ALIAS_FLAG);scorePaint.setStyle(Paint.Style.STROKE);scorePaint.setStrokeCap(Paint.Cap.ROUND);scorePaint.setColor(Color.parseColor("#DDDDDD"));scorePaint.setStrokeWidth(dp2px(0.5f));baseLinePath = new Path();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);sumHeight = getMeasuredHeight();sumWidth = getMeasuredWidth();}private void measure() {maxTime = maxY;//最大为300for (int i = 0; i < dataList.size(); i++) {if (maxTime <= dataList.get(i)) {maxTime = dataList.get(i);}}if (maxTime < 20) {maxTime = 20;}String text = "V";Rect rect = new Rect();textPaint.getTextBounds(text, 0, text.length(), rect);oneHeight = ((sumHeight - buttomHeiht - 2 * rect.height()) / maxTime);oneWidth = sumWidth / 28;}/*** 设置最大最小值*/public void setMaxMin(float max, float min, float center, String unit) {this.maxY = max;this.minY = min;this.centerY = center;this.unitY = unit;}/*** 更新阅读时间*/public void updateTime(ArrayList<Float> timeList, ArrayList<String> bottomList) {this.dataList = timeList;this.timeList = bottomList;if (this.dataList != null && this.dataList.size() > 0 && timeList != null && timeList.size() > 0) {invalidate();}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (dataList == null || timeList == null) return;maxTime = getMaxTime(dataList);measure();toGetXy();//获取x和y的坐标toDrawLine(canvas);}private void toGetXy() {int leftWidth = dp2px(13);//距离右边宽度xyList = new ArrayList<>();for (int i = 0; i < dataList.size(); i++) {float x = oneWidth + i * 4 * oneWidth;float time = dataList.get(i);//每点时间float y = (sumHeight - (oneHeight * time));xyList.add(new PointF(x + leftWidth, y - buttomHeiht));}}/*** 画线*/private void toDrawLine(Canvas canvas) {if (xyList == null || xyList.size() == 0) {return;}List<PointF> NewPoints = new ArrayList<>();NewPoints.addAll(xyList);float lX = 0;float lY = 0;baseLinePath.reset();baseLinePath.moveTo(NewPoints.get(0).x, NewPoints.get(0).y);for (int i = 1; i < NewPoints.size(); i++) {PointF p = NewPoints.get(i);PointF firstPointF = NewPoints.get(i - 1);float x1 = firstPointF.x + lX;float y1 = firstPointF.y + lY;PointF secondPointF = NewPoints.get(i + 1 < NewPoints.size() ? i + 1 : i);lX = (secondPointF.x - firstPointF.x) / 2 * smoothness;lY = (secondPointF.y - firstPointF.y) / 2 * smoothness;float x2 = p.x - lX;float y2 = p.y - lY;if (y1 == p.y) {y2 = y1;}baseLinePath.cubicTo(x1, y1, x2, y2, p.x, p.y);}canvas.drawPath(baseLinePath, mPaint);if (timeList.size() > 1) {for (int i = 0; i < timeList.size(); i++) {float x = NewPoints.get(i).x;float y = NewPoints.get(i).y;float time = dataList.get(i);String mThumbText = String.valueOf(time);Rect rect = new Rect();linePaint.getTextBounds(mThumbText, 0, mThumbText.length(), rect);canvas.drawText(mThumbText, x - rect.width() / 2, y - dp2px(6), linePaint);//画最上面字体canvas.drawCircle(x, y, dp2px(3), circlePaint);canvas.drawCircle(x, y, dp2px(2), circlePaint2);Rect rectf = new Rect();textPaint.getTextBounds(timeList.get(i), 0, timeList.get(i).length(), rectf);canvas.drawText(timeList.get(i), x - rectf.width() / 2, sumHeight - dp2px(2), textPaint);//画最下方的字体}drawArea(canvas, NewPoints);}drawBottomLine(canvas);drawLine(canvas);}/*** 分割线** @param canvas*/private void drawLine(Canvas canvas) {//String text = minY + "";Rect rect = new Rect();scorePaint.getTextBounds(text, 0, text.length(), rect);//0canvas.drawText(text, 0, sumHeight - buttomHeiht - rect.height() / 2, textPaint);//60text = centerY + "";float y = (sumHeight - (oneHeight * centerY));canvas.drawText(text, 0, y - buttomHeiht - rect.height() / 2 - dp2px(4), textPaint);canvas.drawLine(0, y - buttomHeiht, sumWidth, y - buttomHeiht, scorePaint);//100text = maxY + "(" + unitY + ")";float y2 = (sumHeight - (oneHeight * maxY));canvas.drawText(text, 0, y2 - buttomHeiht - rect.height() / 2 - dp2px(4), textPaint);canvas.drawLine(0, y2 - buttomHeiht, sumWidth, y2 - buttomHeiht, scorePaint);}/*** 底部标线** @param canvas*/private void drawBottomLine(Canvas canvas) {Rect rect = new Rect();scorePaint.getTextBounds("0", 0, "0".length(), rect);canvas.drawLine(0, sumHeight - dp2px(15) - rect.height() / 2, sumWidth, sumHeight - dp2px(15) - rect.height() / 2, scorePaint);//画底部灰线}/*** 阴影层叠** @param canvas* @param Points*/private void drawArea(Canvas canvas, List<PointF> Points) {LinearGradient mShader = new LinearGradient(0, 0, 0, getMeasuredHeight(), new int[]{Color.parseColor(nodeColor), Color.parseColor(barLineColor), Color.parseColor(barLineDanColor)}, new float[]{0.5f, 0.65f, 0.85f}, Shader.TileMode.REPEAT);baseShadow.setShader(mShader);if (Points.size() > 0 && xyList != null && xyList.size() > 0) {baseLinePath.lineTo(xyList.get(Points.size() - 1).x, sumHeight - buttomHeiht);baseLinePath.lineTo(xyList.get(0).x, sumHeight - buttomHeiht);baseLinePath.close();canvas.drawPath(baseLinePath, baseShadow);}}public int dp2px(float dp) {final float scale = this.getResources().getDisplayMetrics().density;return (int) (dp * scale + 0.5f);}/*** 取出时间里面的最大的一个用来计算总长度** @param timeList* @return*/public float getMaxTime(List<Float> timeList) {maxTime = 0;for (int i = 0; i < timeList.size(); i++) {if (maxTime < timeList.get(i)) {maxTime = timeList.get(i);}}if (maxTime <= 10) {maxTime = 10;}maxTime *= 1.2;return maxTime;}public int dp2px(Context context, float dp) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dp * scale + 0.5f);}public float dp2px(Resources resources, float dp) {final float scale = resources.getDisplayMetrics().density;return dp * scale + 0.5f;}public float sp2px(Resources resources, float sp) {final float scale = resources.getDisplayMetrics().scaledDensity;return sp * scale;}
}

以上就是全部实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/13493.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

django-vue-admin curd_demo 快速crud教程

django-vue-admin curd_demo 快速crud教程 快速CRUD开发教程&#xff1a;https://bbs.django-vue-admin.com/article/9.html 如何在 env.py 文件配置Mysql数据库&#xff1a;https://bbs.django-vue-admin.com/question/4.html 导入导出配置教程&#xff1a;https://bbs.djang…

Python 中的二维插值

本文展示了如何在 Python 中进行插值&#xff0c;并研究了不同的 2d 实现方法。 我们将讨论用于双变量插值的有用函数&#xff0c;例如 scipy.interpolate.interp2d、numpy.meshgrid 和 Python 中使用的用于平滑/插值 (RBF) 的径向基函数。 我们将使用 SciPy 和 Numpy 库实现插…

OpenCV读取一张深度图像并显示

#include <iostream> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> #include

安全 --- http报文包详解及burp简单使用

HTTP HTTP&#xff08;超文本传输协议&#xff09;是今天所有web应用程序使用的通信协议。最初HTTP只是一个为了获取基本文本的静态资源而开发的简单协议&#xff0c;后来对其进行扩展和利用&#xff0c;使其发展为能够支持如今常见的复杂分布式应用程序。 &#xff08;1&…

【c++】并行编程:cuda入门

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍cuda入门。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路&#x1f95e…

能源结构变更图,传统能源结构对比新兴能源

以传统的能源&#xff08;煤、天然气&#xff09;提供能源&#xff0c;到新兴能源 目前新兴能源以 太阳能&#xff0c;风能为主以及其它行业&#xff0c; 一类企业以新兴能源这种为主&#xff0c;核心是能源接收&#xff0c;以及储存能源&#xff0c;存储通常两种方式&#x…

UE5、CesiumForUnreal接入XYZ格式地图瓦片如高德地图、OSM、ArcGIS等

文章目录 1.实现目标2.实现过程2.1 XYZ与TMS对比2.1 cesium-native改造2.3 CesiumForUnreal插件改造2.4 XYZ瓦片加载测试3.参考资料1.实现目标 通过改造cesium-native和cesiumforunreal插件,参考tms的栅格地图瓦片加载逻辑,实现在UE5、CesiumForUnreal中接入XYZ格式的地图瓦片…

mysql练习---对表进行插入、更新与删除

环境&#xff1a; 第一题 (1) 创建表 create table pet( name varchar(20) not null comment 宠物名称, owner varchar(20) comment 宠物主人, species varchar(20) not null comment 种类, sex char not null comment 性别, birth year not null comment 出生日期, death …

游戏引擎的cpu/gpu粒子系统设计思想

开篇 网上有很多篇粒子系统源码解析&#xff0c;但是只是简单的接口罗列&#xff0c;没有从最原理出发去讲清楚粒子系统的来龙去脉&#xff0c;我将从粒子系统的本质去讲清楚它的设计理念&#xff0c;当理解了它的理念以后&#xff0c;很多粒子遇到的问题就会迎刃解决了&#…

3 STM32标准库函数 之 窗口看门狗(WWDG)所有函数的介绍及使用

3 STM32标准库函数 之 窗口看门狗&#xff08;WWDG&#xff09;所有函数的介绍及使用 1. 图片有格式2 文字无格式三 库函数之窗口看门狗&#xff08;WWDG&#xff09;所有函数的介绍及使用前言一、IWDG库函数固件库函数预览1.1 函 数 IWDG_WriteAccessCmd1.1.1 IWDG_WriteAcces…

IDEA完全免费AI辅助编程插件BITO-GPT4安装及中文国产化设置

打开IDEA的plugins 搜索BITO&#xff1a; 下载后右边工具栏上会出现BITO的小蓝标&#xff0c;这样就可以使用了但是里面是全英文的 设置中文 1.打开BITO点击右上角设置 点击里面的Settings 进入BITO的Web网页 右边这个改成中文&#xff1a; 这样回到IDEA AI就会生成中…

0126 线性表

目录 2.线性表 2.1线性表的定义和基本概念 2.1部分习题 2.2线性表的顺序表示 2.2部分习题 2.3线性表的链式表示 2.3部分习题 2.线性表 2.1线性表的定义和基本概念 2.1部分习题 1.线性表是具有n个&#xff08;&#xff09;的有限序列 A.数据表 B.字符 C.…