可以分4天做任务的网站,西安高科鱼化建设有限公司网站,怀化网站优匿,wordpress搬家后图片打不开文章的目的为了记录使用java 进行android app 开发学习的经历。本职为嵌入式软件开发#xff0c;公司安排开发app#xff0c;临时学习#xff0c;完成app的开发。开发流程和要点有些记忆模糊#xff0c;赶紧记录#xff0c;防止忘记。 相关链接#xff1a;
开源 java an… 文章的目的为了记录使用java 进行android app 开发学习的经历。本职为嵌入式软件开发公司安排开发app临时学习完成app的开发。开发流程和要点有些记忆模糊赶紧记录防止忘记。 相关链接
开源 java android app 开发一开发环境的搭建-CSDN博客
开源 java android app 开发二工程文件结构-CSDN博客
开源 java android app 开发三GUI界面布局和常用组件-CSDN博客
开源 java android app 开发四GUI界面重要组件-CSDN博客
开源 java android app 开发五文件和数据库存储-CSDN博客
开源 java android app 开发六多媒体使用-CSDN博客
开源 java android app 开发七通讯之Tcp和Http-CSDN博客
开源 java android app 开发八通讯之Mqtt和Ble-CSDN博客
开源 java android app 开发九后台之线程和服务-CSDN博客
开源 java android app 开发十广播机制-CSDN博客
开源 java android app 开发十一调试、发布-CSDN博客
开源 java android app 开发十二封库.aar-CSDN博客
开源 java android app 开发十三自定义绘图控件--游戏摇杆
开源 java android app 开发十四自定义绘图控件--波形图
开源 java android app 开发十五自定义绘图控件--仪表盘
开源 java android app 开发十六自定义绘图控件--圆环
推荐链接
开源C# .net mvc 开发一WEB搭建_c#部署web程序-CSDN博客
开源 C# .net mvc 开发二网站快速搭建_c#网站开发-CSDN博客
开源 C# .net mvc 开发三WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客
开源 C# .net mvc 开发四工程结构、页面提交以及显示_c#工程结构-CSDN博客
开源 C# .net mvc 开发五常用代码快速开发_c# mvc开发-CSDN博客 本章节主要内容是:自定义的仪表盘控件的使用随机指向速度。
1.代码分析
2.所有源码
3.效果图 一、代码分析
DashboardView 自定义仪表盘视图详细分析 1. 类定义和常量声明 public class DashboardView extends View {// 默认颜色值常量private static final int DEFAULT_DIAL_COLOR Color.parseColor(#3F51B5);private static final int DEFAULT_NEEDLE_COLOR Color.parseColor(#FF4081);private static final int DEFAULT_TEXT_COLOR Color.parseColor(#212121);private static final int DEFAULT_BG_COLOR Color.parseColor(#FFFFFF); 功能分析
继承自View基类实现自定义视图
定义4个默认颜色常量使用Material Design配色方案
Color.parseColor()将十六进制颜色字符串转换为整型颜色值
2. 成员变量定义 2.1 绘制对象 private Paint dialPaint; // 表盘圆弧画笔
private Paint needlePaint; // 指针画笔
private Paint textPaint; // 文字画笔
private Paint bgPaint; // 背景画笔 2.2 自定义属性 private String title 仪表盘; // 标题文本
private int dialColor; // 表盘颜色
private int needleColor; // 指针颜色
private int textColor; // 文字颜色
private int backgroundColor; // 背景颜色 2.3 数据范围 private float currentValue 0; // 当前显示值
private float minValue 0; // 最小值
private float maxValue 100; // 最大值
private float targetValue 0; // 动画目标值 2.4 动画控制
private boolean isAnimating false; // 动画状态标志
private static final long ANIMATION_DURATION 500; // 动画时长500ms
private long animationStartTime 0; // 动画开始时间戳 3. 构造函数 3.1 单参数构造函数
public DashboardView(Context context) {super(context);init(null); // 调用初始化方法无属性集
} 功能 用于代码动态创建视图时的构造函数
3.2 双参数构造函数
public DashboardView(Context context, Nullable AttributeSet attrs) {super(context, attrs);init(attrs); // 传入XML属性集
} 功能 用于XML布局文件中引用的标准构造函数
3.3 三参数构造函数
public DashboardView(Context context, Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(attrs); // 包含默认样式属性
} 功能 支持样式属性的构造函数
4. init() 初始化函数
private void init(AttributeSet attrs) {// 获取自定义属性if (attrs ! null) {TypedArray a getContext().obtainStyledAttributes(attrs, R.styleable.DashboardView);title a.getString(R.styleable.DashboardView_title);dialColor a.getColor(R.styleable.DashboardView_dialColor, DEFAULT_DIAL_COLOR);needleColor a.getColor(R.styleable.DashboardView_needleColor, DEFAULT_NEEDLE_COLOR);textColor a.getColor(R.styleable.DashboardView_textColor, DEFAULT_TEXT_COLOR);backgroundColor a.getColor(R.styleable.DashboardView_backgroundColor, DEFAULT_BG_COLOR);a.recycle(); // 必须回收TypedArray} else {// 使用默认值dialColor DEFAULT_DIAL_COLOR;// ... 其他颜色初始化}// 初始化表盘画笔dialPaint new Paint(Paint.ANTI_ALIAS_FLAG); // 启用抗锯齿dialPaint.setColor(dialColor);dialPaint.setStyle(Paint.Style.STROKE); // 描边模式dialPaint.setStrokeWidth(10f); // 线宽10像素// 初始化指针画笔needlePaint new Paint(Paint.ANTI_ALIAS_FLAG);needlePaint.setColor(needleColor);needlePaint.setStyle(Paint.Style.FILL_AND_STROKE); // 填充和描边needlePaint.setStrokeWidth(5f); // 线宽5像素// 初始化文字画笔textPaint new Paint(Paint.ANTI_ALIAS_FLAG);textPaint.setColor(textColor);textPaint.setTextSize(40); // 文字大小40pxtextPaint.setTextAlign(Paint.Align.CENTER); // 文字居中对齐// 初始化背景画笔bgPaint new Paint(Paint.ANTI_ALIAS_FLAG);bgPaint.setColor(backgroundColor);bgPaint.setStyle(Paint.Style.FILL); // 填充模式
} 功能分析
属性解析 使用TypedArray读取XML中定义的属性值
资源回收 必须调用recycle()释放资源
画笔配置 为不同绘制元素创建专用的Paint对象
抗锯齿 所有画笔都启用抗锯齿以获得平滑效果5. onDraw() 核心绘制函数
Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas); // 调用父类绘制// 计算基本几何参数int width getWidth();int height getHeight();int centerX width / 2; // 中心点X坐标int centerY height / 2; // 中心点Y坐标 int radius Math.min(width, height) / 2 - 20; // 表盘半径留出边距// 1. 绘制背景圆形canvas.drawCircle(centerX, centerY, radius 20, bgPaint);// 2. 绘制表盘圆弧RectF oval new RectF(centerX - radius, centerY - radius, centerX radius, centerY radius);canvas.drawArc(oval, 150, 240, false, dialPaint); // 从150°开始绘制240°圆弧// 3. 绘制刻度线和刻度值drawScale(canvas, centerX, centerY, radius);// 4. 绘制指针drawNeedle(canvas, centerX, centerY, radius);// 5. 绘制标题文字canvas.drawText(title, centerX, centerY radius 60, textPaint);// 6. 绘制当前数值加大字号textPaint.setTextSize(50); // 临时调整字号canvas.drawText(String.format(%.1f, currentValue), centerX, centerY 20, textPaint);textPaint.setTextSize(40); // 恢复原字号// 7. 动画处理逻辑if (isAnimating) {long currentTime System.currentTimeMillis();float elapsed currentTime - animationStartTime; // 已过去的时间if (elapsed ANIMATION_DURATION) {float progress elapsed / ANIMATION_DURATION; // 动画进度(0-1)// 线性插值计算当前值currentValue currentValue (targetValue - currentValue) * progress;invalidate(); // 请求重绘实现动画帧} else {currentValue targetValue; // 动画结束直接跳到目标值isAnimating false; // 停止动画}}
} 6. drawScale() 刻度绘制函数
private void drawScale(Canvas canvas, int centerX, int centerY, int radius) {Paint scalePaint new Paint(Paint.ANTI_ALIAS_FLAG);scalePaint.setColor(textColor);scalePaint.setTextSize(30);scalePaint.setTextAlign(Paint.Align.CENTER);// 绘制11个刻度0-10包含两端for (int i 0; i 10; i) {// 计算刻度角度起始150° 每刻度24°总240°范围float angle 150 (i * 24);// 计算对应数值最小值 等分比例float value minValue (maxValue - minValue) * i / 10;// 将角度转换为弧度double startAngleRad Math.toRadians(angle);// 计算刻度线起点向内偏移20pxint startX centerX (int) ((radius - 20) * Math.cos(startAngleRad));int startY centerY (int) ((radius - 20) * Math.sin(startAngleRad));// 计算刻度线终点表盘边缘int endX centerX (int) (radius * Math.cos(startAngleRad));int endY centerY (int) (radius * Math.sin(startAngleRad));// 绘制刻度线canvas.drawLine(startX, startY, endX, endY, scalePaint);// 计算刻度值文字位置向内偏移50pxint textX centerX (int) ((radius - 50) * Math.cos(startAngleRad));int textY centerY (int) ((radius - 50) * Math.sin(startAngleRad)) 10;// 绘制刻度数值取整显示canvas.drawText(String.valueOf((int)value), textX, textY, scalePaint);}
} 7. drawNeedle() 指针绘制函数
private void drawNeedle(Canvas canvas, int centerX, int centerY, int radius) {// 计算指针角度150°对应minValue390°对应maxValue实际是150°240°float angle 150 (currentValue - minValue) / (maxValue - minValue) * 240;double angleRad Math.toRadians(angle); // 转换为弧度// 计算指针终点坐标向内偏移30pxint endX centerX (int) ((radius - 30) * Math.cos(angleRad));int endY centerY (int) ((radius - 30) * Math.sin(angleRad));// 绘制指针线段从中心到终点canvas.drawLine(centerX, centerY, endX, endY, needlePaint);// 绘制中心圆点半径10pxcanvas.drawCircle(centerX, centerY, 10, needlePaint);
} 8. setValue() 数值设置函数带动画
public void setValue(float value) {// 边界检查if (value minValue) value minValue;if (value maxValue) value maxValue;// 设置动画参数this.targetValue value; // 目标值this.isAnimating true; // 启动动画标志this.animationStartTime System.currentTimeMillis(); // 记录开始时间invalidate(); // 触发重绘启动动画
} 9. 其他设置函数
// 设置数值范围
public void setRange(float min, float max) {this.minValue min;this.maxValue max;invalidate(); // 重绘视图
}// 设置标题
public void setTitle(String title) {this.title title;invalidate();
}// 颜色设置函数都会更新对应画笔颜色并重绘
public void setDialColor(int color) {this.dialColor color;dialPaint.setColor(color);invalidate();
}// 获取当前值
public float getCurrentValue() {return currentValue;
} 10. 关键设计特点 10.1 动画实现机制 线性插值 使用currentValue (targetValue - currentValue) * progress计算过渡值
时间控制 基于系统时间戳计算动画进度
连续重绘 通过invalidate()在动画期间持续刷新视图
10.2 几何计算 角度映射 将数值线性映射到150°-390°的角度范围
坐标转换 使用三角函数计算圆周上的点坐标
自适应尺寸 基于视图实际尺寸计算绘制参数
10.3 绘制层次 背景圆形
表盘圆弧
刻度线和数值
指针和中心点
标题和当前值文字
这个自定义视图实现了完整的仪表盘功能具有良好的可定制性和平滑的动画效果 二、所有源码
文件结构
DashboardView.java
MainActivity.java
activity_main.xml
attrs.xml
colors.xml 1.DashboardView.java源码
package com.example.dashboard;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;public class DashboardView extends View {// 默认颜色值private static final int DEFAULT_DIAL_COLOR Color.parseColor(#3F51B5);private static final int DEFAULT_NEEDLE_COLOR Color.parseColor(#FF4081);private static final int DEFAULT_TEXT_COLOR Color.parseColor(#212121);private static final int DEFAULT_BG_COLOR Color.parseColor(#FFFFFF);// 绘制相关对象private Paint dialPaint;private Paint needlePaint;private Paint textPaint;private Paint bgPaint;// 自定义属性private String title 仪表盘;private int dialColor;private int needleColor;private int textColor;private int backgroundColor;// 数据相关private float currentValue 0;private float minValue 0;private float maxValue 100;private float targetValue 0;// 动画相关private boolean isAnimating false;private static final long ANIMATION_DURATION 500; // 动画持续时间(ms)private long animationStartTime 0;public DashboardView(Context context) {super(context);init(null);}public DashboardView(Context context, Nullable AttributeSet attrs) {super(context, attrs);init(attrs);}public DashboardView(Context context, Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(attrs);}private void init(AttributeSet attrs) {// 获取自定义属性if (attrs ! null) {TypedArray a getContext().obtainStyledAttributes(attrs, R.styleable.DashboardView);title a.getString(R.styleable.DashboardView_title);dialColor a.getColor(R.styleable.DashboardView_dialColor, DEFAULT_DIAL_COLOR);needleColor a.getColor(R.styleable.DashboardView_needleColor, DEFAULT_NEEDLE_COLOR);textColor a.getColor(R.styleable.DashboardView_textColor, DEFAULT_TEXT_COLOR);backgroundColor a.getColor(R.styleable.DashboardView_backgroundColor, DEFAULT_BG_COLOR);a.recycle();} else {dialColor DEFAULT_DIAL_COLOR;needleColor DEFAULT_NEEDLE_COLOR;textColor DEFAULT_TEXT_COLOR;backgroundColor DEFAULT_BG_COLOR;}// 初始化表盘画笔dialPaint new Paint(Paint.ANTI_ALIAS_FLAG);dialPaint.setColor(dialColor);dialPaint.setStyle(Paint.Style.STROKE);dialPaint.setStrokeWidth(10f);// 初始化指针画笔needlePaint new Paint(Paint.ANTI_ALIAS_FLAG);needlePaint.setColor(needleColor);needlePaint.setStyle(Paint.Style.FILL_AND_STROKE);needlePaint.setStrokeWidth(5f);// 初始化文字画笔textPaint new Paint(Paint.ANTI_ALIAS_FLAG);textPaint.setColor(textColor);textPaint.setTextSize(40);textPaint.setTextAlign(Paint.Align.CENTER);// 初始化背景画笔bgPaint new Paint(Paint.ANTI_ALIAS_FLAG);bgPaint.setColor(backgroundColor);bgPaint.setStyle(Paint.Style.FILL);}Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int width getWidth();int height getHeight();int centerX width / 2;int centerY height / 2;int radius Math.min(width, height) / 2 - 20;// 绘制背景canvas.drawCircle(centerX, centerY, radius 20, bgPaint);// 绘制表盘RectF oval new RectF(centerX - radius, centerY - radius, centerX radius, centerY radius);canvas.drawArc(oval, 150, 240, false, dialPaint);// 绘制刻度drawScale(canvas, centerX, centerY, radius);// 绘制指针drawNeedle(canvas, centerX, centerY, radius);// 绘制标题canvas.drawText(title, centerX, centerY radius 60, textPaint);// 绘制当前值textPaint.setTextSize(50);canvas.drawText(String.format(%.1f, currentValue), centerX, centerY 20, textPaint);textPaint.setTextSize(40);// 如果需要动画继续重绘if (isAnimating) {long currentTime System.currentTimeMillis();float elapsed currentTime - animationStartTime;if (elapsed ANIMATION_DURATION) {float progress elapsed / ANIMATION_DURATION;currentValue currentValue (targetValue - currentValue) * progress;invalidate();} else {currentValue targetValue;isAnimating false;}}}private void drawScale(Canvas canvas, int centerX, int centerY, int radius) {Paint scalePaint new Paint(Paint.ANTI_ALIAS_FLAG);scalePaint.setColor(textColor);scalePaint.setTextSize(30);scalePaint.setTextAlign(Paint.Align.CENTER);for (int i 0; i 10; i) {float angle 150 (i * 24);float value minValue (maxValue - minValue) * i / 10;// 计算刻度起点和终点double startAngleRad Math.toRadians(angle);int startX centerX (int) ((radius - 20) * Math.cos(startAngleRad));int startY centerY (int) ((radius - 20) * Math.sin(startAngleRad));int endX centerX (int) (radius * Math.cos(startAngleRad));int endY centerY (int) (radius * Math.sin(startAngleRad));// 绘制刻度线canvas.drawLine(startX, startY, endX, endY, scalePaint);// 绘制刻度值int textX centerX (int) ((radius - 50) * Math.cos(startAngleRad));int textY centerY (int) ((radius - 50) * Math.sin(startAngleRad)) 10;canvas.drawText(String.valueOf((int)value), textX, textY, scalePaint);}}private void drawNeedle(Canvas canvas, int centerX, int centerY, int radius) {// 计算指针角度 (150°到390°对应minValue到maxValue)float angle 150 (currentValue - minValue) / (maxValue - minValue) * 240;double angleRad Math.toRadians(angle);// 计算指针终点int endX centerX (int) ((radius - 30) * Math.cos(angleRad));int endY centerY (int) ((radius - 30) * Math.sin(angleRad));// 绘制指针canvas.drawLine(centerX, centerY, endX, endY, needlePaint);// 绘制中心圆点canvas.drawCircle(centerX, centerY, 10, needlePaint);}// 设置当前值带动画效果public void setValue(float value) {if (value minValue) value minValue;if (value maxValue) value maxValue;this.targetValue value;this.isAnimating true;this.animationStartTime System.currentTimeMillis();invalidate();}// 设置数值范围public void setRange(float min, float max) {this.minValue min;this.maxValue max;invalidate();}// 设置标题public void setTitle(String title) {this.title title;invalidate();}// 设置表盘颜色public void setDialColor(int color) {this.dialColor color;dialPaint.setColor(color);invalidate();}// 设置指针颜色public void setNeedleColor(int color) {this.needleColor color;needlePaint.setColor(color);invalidate();}// 设置文字颜色public void setTextColor(int color) {this.textColor color;textPaint.setColor(color);invalidate();}// 设置背景颜色public void setBackgroundColor(int color) {this.backgroundColor color;bgPaint.setColor(color);invalidate();}public float getCurrentValue() {return currentValue;}
}2.MainActivity.java源码
package com.example.dashboard;import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import java.util.Random;public class MainActivity extends AppCompatActivity {private DashboardView dashboard;private TextView valueText;private Handler handler new Handler();private Random random new Random();private float minValue 0;private float maxValue 100;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);dashboard findViewById(R.id.dashboard);valueText findViewById(R.id.valueText);// 设置仪表盘属性dashboard.setTitle(速度仪表盘);dashboard.setDialColor(getResources().getColor(R.color.dialColor));dashboard.setNeedleColor(getResources().getColor(R.color.needleColor));dashboard.setTextColor(getResources().getColor(R.color.textColor));dashboard.setBackgroundColor(getResources().getColor(R.color.backgroundColor));dashboard.setRange(minValue, maxValue);// 开始定时更新数据startDataUpdates();}private void startDataUpdates() {handler.postDelayed(new Runnable() {Overridepublic void run() {// 生成随机值float value minValue random.nextFloat() * (maxValue - minValue);// 更新仪表盘dashboard.setValue(value);// 更新文本显示valueText.setText(String.format(当前值: %.1f, value));// 1秒后再次更新handler.postDelayed(this, 1000);}}, 1000);}Overrideprotected void onDestroy() {super.onDestroy();// 移除所有回调防止内存泄漏handler.removeCallbacksAndMessages(null);}
}3.activity_main.xml源码
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticalandroid:gravitycenterandroid:padding16dptools:context.MainActivitycom.example.dashboard.DashboardViewandroid:idid/dashboardandroid:layout_width300dpandroid:layout_height300dpapp:title速度仪表盘app:dialColor#3F51B5app:needleColor#FF4081app:textColor#212121app:backgroundColor#FFFFFF /TextViewandroid:idid/valueTextandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginTop20dpandroid:text当前值: 0.0android:textSize18sp //LinearLayout 4.attrs.xml源码用于主活动设置控件的属性
?xml version1.0 encodingutf-8?
resourcesdeclare-styleable nameDashboardViewattr nametitle formatstring /attr namedialColor formatcolor /attr nameneedleColor formatcolor /attr nametextColor formatcolor /attr namebackgroundColor formatcolor //declare-styleable
/resources 5.colors.xml源码用途添加的各种颜色
?xml version1.0 encodingutf-8?
resourcescolor namecolorPrimary#008577/colorcolor namecolorPrimaryDark#00574B/colorcolor namecolorAccent#D81B60/colorcolor namepurple_200#FFBB86FC/colorcolor namepurple_500#FF6200EE/colorcolor namepurple_700#FF3700B3/colorcolor nameteal_200#FF03DAC5/colorcolor nameteal_700#FF018786/colorcolor nameblack#FF000000/colorcolor namewhite#FFFFFFFF/color!-- 仪表盘自定义颜色 --color namedialColor#3F51B5/colorcolor nameneedleColor#FF4081/colorcolor nametextColor#212121/colorcolor namebackgroundColor#FFFFFF/color/resources三、效果演示
主活动随机写入数据指针指向仪表盘的相应位置。