文章的目的为了记录使用java 进行android app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 java android app 开发(一)开发环境的搭建-优快云博客
开源 java android app 开发(二)工程文件结构-优快云博客
开源 java android app 开发(三)GUI界面布局和常用组件-优快云博客
开源 java android app 开发(四)GUI界面重要组件-优快云博客
开源 java android app 开发(五)文件和数据库存储-优快云博客
开源 java android app 开发(六)多媒体使用-优快云博客
开源 java android app 开发(七)通讯之Tcp和Http-优快云博客
开源 java android app 开发(八)通讯之Mqtt和Ble-优快云博客
开源 java android app 开发(九)后台之线程和服务-优快云博客
开源 java android app 开发(十)广播机制-优快云博客
开源 java android app 开发(十一)调试、发布-优快云博客
开源 java android app 开发(十二)封库.aar-优快云博客
开源 java android app 开发(十三)自定义绘图控件--游戏摇杆
开源 java android app 开发(十四)自定义绘图控件--波形图
开源 java android app 开发(十五)自定义绘图控件--仪表盘
开源 java android app 开发(十六)自定义绘图控件--圆环
推荐链接:
开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-优快云博客
开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-优快云博客
开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-优快云博客
开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-优快云博客
开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-优快云博客
本章节主要内容是:自定义的圆环控件的使用,随机指向速度。
1.代码分析
2.所有源码
3.效果演示
一、代码分析
DataBoard 自定义视图详细分析
1. 类结构和成员变量
1.1 默认常量定义
private static final int DEFAULT_OUTER_DIAMETER = 200; // dp
private static final int DEFAULT_RING_WIDTH = 20; // dp
// ... 其他默认值
定义了所有可配置参数的默认值
尺寸单位使用dp,颜色使用Android系统常量
1.2 绘制相关对象
private Paint mRingPaint; // 圆环画笔
private Paint mTextPaint; // 文字画笔
private RectF mRingRect; // 圆环绘制区域
private Rect mTextBounds; // 文字边界测量
1.3 自定义属性变量
private float mOuterDiameter; // 外径
private float mRingWidth; // 圆环宽度
private int mRingBaseColor; // 基础圆环颜色
// ... 其他属性
2. 构造函数和初始化
2.1 构造函数链
java
public DataBoard(Context context) {
this(context, null);
}
public DataBoard(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DataBoard(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
遵循Android自定义View的标准构造函数模式
最终都调用init()方法进行统一初始化
2.2 init() 方法
private void init(Context context, AttributeSet attrs) {
// 密度转换
float density = getResources().getDisplayMetrics().density;
mOuterDiameter = DEFAULT_OUTER_DIAMETER * density;
mRingWidth = DEFAULT_RING_WIDTH * density;
// ... 其他默认值设置
// 自定义属性处理
if (attrs != null) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DataBoard);
mOuterDiameter = ta.getDimension(R.styleable.DataBoard_db_outerDiameter, mOuterDiameter);
// ... 逐个获取属性值
ta.recycle(); // 重要:必须回收TypedArray
}
// 画笔初始化
mRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRingPaint.setStyle(Paint.Style.STROKE);
mRingPaint.setStrokeWidth(mRingWidth);
mRingPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角端点
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setTextAlign(Paint.Align.CENTER); // 文字水平居中
// 矩形区域初始化
mRingRect = new RectF();
mTextBounds = new Rect();
setBackgroundColor(Color.WHITE);
}
3. 视图测量和布局
3.1 onMeasure() 方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 计算期望尺寸(包含padding)
int desiredWidth = (int) mOuterDiameter + getPaddingLeft() + getPaddingRight();
int desiredHeight = (int) mOuterDiameter + getPaddingTop() + getPaddingBottom();
// 获取测量模式和尺寸
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width, height;
// 宽度测量逻辑
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize; // 父视图指定确切尺寸
} else if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(desiredWidth, widthSize); // 不能超过父视图限制
} else {
width = desiredWidth; // 未指定限制,使用期望尺寸
}
// 高度测量逻辑(同上)
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(desiredHeight, heightSize);
} else {
height = desiredHeight;
}
setMeasuredDimension(width, height);
}
3.2 onSizeChanged() 方法
java
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 计算中心点坐标
mCenterX = w / 2f;
mCenterY = h / 2f;
// 计算可用空间(考虑padding)
float availableWidth = w - getPaddingLeft() - getPaddingRight();
float availableHeight = h - getPaddingTop() - getPaddingBottom();
// 计算半径(缩小10%并考虑圆环宽度)
float sizeReduction = 0.1f;
float reducedSize = Math.min(availableWidth, availableHeight) * (1 - sizeReduction);
mRadius = reducedSize / 2f - mRingWidth / 2f; // 减去圆环宽度的一半
// 设置圆环绘制区域
float left = mCenterX - mRadius;
float top = mCenterY - mRadius;
float right = mCenterX + mRadius;
float bottom = mCenterY + mRadius;
mRingRect.set(left, top, right, bottom);
}
4. 绘制方法详解
4.1 onDraw() 主绘制方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawRingEdges(canvas); // 1. 绘制渐变边缘
drawBaseRing(canvas); // 2. 绘制基础圆环
drawDataRing(canvas); // 3. 绘制数据圆环
drawCenterText(canvas); // 4. 绘制中心文字
}
4.2 drawRingEdges() - 渐变边缘绘制
java
private void drawRingEdges(Canvas canvas) {
Paint edgePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
edgePaint.setStyle(Paint.Style.STROKE);
// 外圈渐变(深灰到黑)
Shader outerShader = new RadialGradient(
mCenterX, mCenterY, mRadius + mRingWidth / 2, // 外圈半径
mOuterStartColor, mOuterEndColor, Shader.TileMode.CLAMP);
edgePaint.setShader(outerShader);
edgePaint.setStrokeWidth(2); // 边缘线宽
canvas.drawCircle(mCenterX, mCenterY, mRadius + mRingWidth / 2, edgePaint);
// 内圈渐变(白到浅灰)
Shader innerShader = new RadialGradient(
mCenterX, mCenterY, mRadius - mRingWidth / 2, // 内圈半径
mInnerStartColor, mInnerEndColor, Shader.TileMode.CLAMP);
edgePaint.setShader(innerShader);
canvas.drawCircle(mCenterX, mCenterY, mRadius - mRingWidth / 2, edgePaint);
}
4.3 drawBaseRing() - 基础圆环绘制
java
private void drawBaseRing(Canvas canvas) {
mRingPaint.setColor(mRingBaseColor);
canvas.drawArc(mRingRect, 0, 360, false, mRingPaint); // 绘制完整圆环
}
4.4 drawDataRing() - 数据圆环绘制
java
private void drawDataRing(Canvas canvas) {
if (mCurrentValue <= 0) return; // 无数据时不绘制
// 计算扫描角度(基于当前值与最大值的比例)
float sweepAngle = (mCurrentValue / mMaxValue) * 360;
sweepAngle = Math.min(sweepAngle, 360); // 限制最大360度
mRingPaint.setColor(mRingDataColor);
// 从270度开始(12点方向),顺时针绘制
canvas.drawArc(mRingRect, 270, sweepAngle, false, mRingPaint);
// 注释掉的半量程颜色变化逻辑
/*
if (mCurrentValue <= mMaxValue / 2) {
// 半量程内使用数据颜色
mRingPaint.setColor(mRingDataColor);
canvas.drawArc(mRingRect, 270, sweepAngle, false, mRingPaint);
} else {
// 超过半量程,后半部分使用基础颜色
float firstHalfAngle = 180;
float secondHalfAngle = sweepAngle - firstHalfAngle;
mRingPaint.setColor(mRingDataColor);
canvas.drawArc(mRingRect, 270, firstHalfAngle, false, mRingPaint);
mRingPaint.setColor(mRingBaseColor);
canvas.drawArc(mRingRect, 270 + firstHalfAngle, secondHalfAngle, false, mRingPaint);
}
*/
}
4.5 drawCenterText() - 中心文字绘制
private void drawCenterText(Canvas canvas) {
// 格式化文本:"当前值/最大值"
String text = String.format("%.1f/% .1f", mCurrentValue, mMaxValue);
// 获取文字边界用于垂直居中计算
mTextPaint.getTextBounds(text, 0, text.length(), mTextBounds);
// 计算垂直居中位置
float textY = mCenterY - (mTextBounds.top + mTextBounds.bottom) / 2f;
canvas.drawText(text, mCenterX, textY, mTextPaint);
}
5. 公共方法(属性设置)
5.1 数值设置方法
public void setCurrentValue(float value) {
mCurrentValue = Math.max(0, Math.min(value, mMaxValue)); // 边界检查
invalidate(); // 请求重绘
}
public void setMaxValue(float maxValue) {
mMaxValue = Math.max(0, maxValue);
if (mCurrentValue > mMaxValue) {
mCurrentValue = mMaxValue; // 调整当前值不超过新最大值
}
invalidate();
}
5.2 样式设置方法
java
public void setRingWidth(float width) {
mRingWidth = width;
mRingPaint.setStrokeWidth(mRingWidth);
requestLayout(); // 需要重新布局(尺寸可能改变)
invalidate(); // 需要重绘
}
public void setOuterDiameter(float diameter) {
mOuterDiameter = diameter;
requestLayout(); // 尺寸改变,需要重新测量布局
invalidate();
}
二、所有源码
需要修改的文件有5个

1. DataBoard.java代码
package com.example.dashboard;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
public class DataBoard extends View {
// 默认值
private static final int DEFAULT_OUTER_DIAMETER = 200; // dp
private static final int DEFAULT_RING_WIDTH = 20; // dp
private static final int DEFAULT_BASE_COLOR = Color.LTGRAY;
private static final int DEFAULT_DATA_COLOR = Color.BLUE;
private static final int DEFAULT_TEXT_COLOR = Color.BLACK;
private static final int DEFAULT_TEXT_SIZE = 16; // sp
private static final float DEFAULT_MAX_VALUE = 100f;
private static final float DEFAULT_CURRENT_VALUE = 0f;
// 绘制相关
private Paint mRingPaint;
private Paint mTextPaint;
private RectF mRingRect;
private Rect mTextBounds;
// 自定义属性
private float mOuterDiameter;
private float mRingWidth;
private int mRingBaseColor;
private int mRingDataColor;
private int mTextColor;
private float mTextSize;
private float mMaxValue;
private float mCurrentValue;
private int mInnerStartColor;
private int mInnerEndColor;
private int mOuterStartColor;
private int mOuterEndColor;
// 计算属性
private float mCenterX;
private float mCenterY;
private float mRadius;
public DataBoard(Context context) {
this(context, null);
}
public DataBoard(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DataBoard(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
// 初始化默认值
float density = getResources().getDisplayMetrics().density;
mOuterDiameter = DEFAULT_OUTER_DIAMETER * density;
mRingWidth = DEFAULT_RING_WIDTH * density;
mRingBaseColor = DEFAULT_BASE_COLOR;
mRingDataColor = DEFAULT_DATA_COLOR;
mTextColor = DEFAULT_TEXT_COLOR;
mTextSize = DEFAULT_TEXT_SIZE * density;
mMaxValue = DEFAULT_MAX_VALUE;
mCurrentValue = DEFAULT_CURRENT_VALUE;
mInnerStartColor = Color.WHITE;
mInnerEndColor = Color.LTGRAY;
mOuterStartColor = Color.DKGRAY;
mOuterEndColor = Color.BLACK;
// 获取自定义属性
if (attrs != null) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DataBoard);
mOuterDiameter = ta.getDimension(R.styleable.DataBoard_db_outerDiameter, mOuterDiameter);
mRingWidth = ta.getDimension(R.styleable.DataBoard_db_ringWidth, mRingWidth);
mRingBaseColor = ta.getColor(R.styleable.DataBoard_db_ringBaseColor, mRingBaseColor);
mRingDataColor = ta.getColor(R.styleable.DataBoard_db_ringDataColor, mRingDataColor);
mTextColor = ta.getColor(R.styleable.DataBoard_db_textColor, mTextColor);
mTextSize = ta.getDimension(R.styleable.DataBoard_db_textSize, mTextSize);
mMaxValue = ta.getFloat(R.styleable.DataBoard_db_maxValue, mMaxValue);
mCurrentValue = ta.getFloat(R.styleable.DataBoard_db_currentValue, mCurrentValue);
mInnerStartColor = ta.getColor(R.styleable.DataBoard_db_innerStartColor, mInnerStartColor);
mInnerEndColor = ta.getColor(R.styleable.DataBoard_db_innerEndColor, mInnerEndColor);
mOuterStartColor = ta.getColor(R.styleable.DataBoard_db_outerStartColor, mOuterStartColor);
mOuterEndColor = ta.getColor(R.styleable.DataBoard_db_outerEndColor, mOuterEndColor);
ta.recycle();
}
// 初始化圆环画笔
mRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRingPaint.setStyle(Paint.Style.STROKE);
mRingPaint.setStrokeWidth(mRingWidth);
mRingPaint.setStrokeCap(Paint.Cap.ROUND);
// 初始化文字画笔
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mRingRect = new RectF();
mTextBounds = new Rect();
// 设置白色背景
setBackgroundColor(Color.WHITE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = (int) mOuterDiameter + getPaddingLeft() + getPaddingRight();
int desiredHeight = (int) mOuterDiameter + getPaddingTop() + getPaddingBottom();
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width, height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(desiredWidth, widthSize);
} else {
width = desiredWidth;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(desiredHeight, heightSize);
} else {
height = desiredHeight;
}
setMeasuredDimension(width, height);
}
/*
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 计算中心点
mCenterX = w / 2f;
mCenterY = h / 2f;
// 计算半径(考虑padding)
float availableWidth = w - getPaddingLeft() - getPaddingRight();
float availableHeight = h - getPaddingTop() - getPaddingBottom();
mRadius = Math.min(availableWidth, availableHeight) / 2f - mRingWidth / 2f;
// 设置圆环绘制区域
float left = mCenterX - mRadius;
float top = mCenterY - mRadius;
float right = mCenterX + mRadius;
float bottom = mCenterY + mRadius;
mRingRect.set(left, top, right, bottom);
}
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 计算中心点
mCenterX = w / 2f;
mCenterY = h / 2f;
// 计算半径(考虑padding和额外的边距)
float availableWidth = w - getPaddingLeft() - getPaddingRight();
float availableHeight = h - getPaddingTop() - getPaddingBottom();
// 设置圆环比可用空间小一些(例如小10%)
float sizeReduction = 0.1f; // 缩小10%
float reducedSize = Math.min(availableWidth, availableHeight) * (1 - sizeReduction);
mRadius = reducedSize / 2f - mRingWidth / 2f;
// 或者固定缩小一定的像素值
// float fixedMargin = 20f; // 缩小20像素
// float baseSize = Math.min(availableWidth, availableHeight);
// mRadius = (baseSize - fixedMargin * 2) / 2f - mRingWidth / 2f;
// 设置圆环绘制区域
float left = mCenterX - mRadius;
float top = mCenterY - mRadius;
float right = mCenterX + mRadius;
float bottom = mCenterY + mRadius;
mRingRect.set(left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制内外径边的渐变效果
drawRingEdges(canvas);
// 绘制基础圆环
drawBaseRing(canvas);
// 绘制数据圆环
drawDataRing(canvas);
// 绘制中心文字
drawCenterText(canvas);
}
private void drawRingEdges(Canvas canvas) {
// 绘制外径边的渐变
Paint edgePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
edgePaint.setStyle(Paint.Style.STROKE);
// 外圈渐变
Shader outerShader = new RadialGradient(
mCenterX, mCenterY, mRadius + mRingWidth / 2,
mOuterStartColor, mOuterEndColor, Shader.TileMode.CLAMP);
edgePaint.setShader(outerShader);
edgePaint.setStrokeWidth(2);
canvas.drawCircle(mCenterX, mCenterY, mRadius + mRingWidth / 2, edgePaint);
// 内圈渐变
Shader innerShader = new RadialGradient(
mCenterX, mCenterY, mRadius - mRingWidth / 2,
mInnerStartColor, mInnerEndColor, Shader.TileMode.CLAMP);
edgePaint.setShader(innerShader);
canvas.drawCircle(mCenterX, mCenterY, mRadius - mRingWidth / 2, edgePaint);
}
private void drawBaseRing(Canvas canvas) {
mRingPaint.setColor(mRingBaseColor);
// 绘制完整的圆环作为背景
canvas.drawArc(mRingRect, 0, 360, false, mRingPaint);
}
private void drawDataRing(Canvas canvas) {
if (mCurrentValue <= 0) return;
// 计算数据对应的角度(270°开始,顺时针)
float sweepAngle = (mCurrentValue / mMaxValue) * 360;
sweepAngle = Math.min(sweepAngle, 360); // 不超过360度
/*
// 判断是否超过半量程
if (mCurrentValue <= mMaxValue / 2) {
// 半量程以内,全部使用数据颜色
mRingPaint.setColor(mRingDataColor);
canvas.drawArc(mRingRect, 270, sweepAngle, false, mRingPaint);
} else {
// 超过半量程,前半部分数据颜色,后半部分基本颜色
float firstHalfAngle = 180; // 前半部分180度
float secondHalfAngle = sweepAngle - firstHalfAngle;
// 绘制前半部分(数据颜色)
mRingPaint.setColor(mRingDataColor);
canvas.drawArc(mRingRect, 270, firstHalfAngle, false, mRingPaint);
// 绘制后半部分(基本颜色)
mRingPaint.setColor(mRingBaseColor);
canvas.drawArc(mRingRect, 270 + firstHalfAngle, secondHalfAngle, false, mRingPaint);
}
*/
mRingPaint.setColor(mRingDataColor);
canvas.drawArc(mRingRect, 270, sweepAngle, false, mRingPaint);
}
private void drawCenterText(Canvas canvas) {
String text = String.format("%.1f/% .1f", mCurrentValue, mMaxValue);
mTextPaint.getTextBounds(text, 0, text.length(), mTextBounds);
// 计算文字垂直居中位置
float textY = mCenterY - (mTextBounds.top + mTextBounds.bottom) / 2f;
canvas.drawText(text, mCenterX, textY, mTextPaint);
}
// 公共方法 - 设置当前值
public void setCurrentValue(float value) {
mCurrentValue = Math.max(0, Math.min(value, mMaxValue));
invalidate();
}
// 公共方法 - 设置最大值
public void setMaxValue(float maxValue) {
mMaxValue = Math.max(0, maxValue);
if (mCurrentValue > mMaxValue) {
mCurrentValue = mMaxValue;
}
invalidate();
}
// 公共方法 - 设置圆环宽度
public void setRingWidth(float width) {
mRingWidth = width;
mRingPaint.setStrokeWidth(mRingWidth);
requestLayout();
invalidate();
}
// 公共方法 - 设置圆环基本颜色
public void setRingBaseColor(int color) {
mRingBaseColor = color;
invalidate();
}
// 公共方法 - 设置圆环数据颜色
public void setRingDataColor(int color) {
mRingDataColor = color;
invalidate();
}
// 公共方法 - 设置文字颜色
public void setTextColor(int color) {
mTextColor = color;
mTextPaint.setColor(mTextColor);
invalidate();
}
// 公共方法 - 设置外圈直径
public void setOuterDiameter(float diameter) {
mOuterDiameter = diameter;
requestLayout();
invalidate();
}
// 获取当前值
public float getCurrentValue() {
return mCurrentValue;
}
// 获取最大值
public float getMaxValue() {
return mMaxValue;
}
}
2. mainactivity.java代码
package com.example.dashboard;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Button;
import android.widget.SeekBar;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private DataBoard dataBoard;
private Button btnIncrease, btnDecrease;
private SeekBar seekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
setupListeners();
}
private void initViews() {
dataBoard = findViewById(R.id.dataBoard);
btnIncrease = findViewById(R.id.btnIncrease);
btnDecrease = findViewById(R.id.btnDecrease);
seekBar = findViewById(R.id.seekBar);
// 设置SeekBar初始值
seekBar.setProgress((int) dataBoard.getCurrentValue());
}
private void setupListeners() {
btnIncrease.setOnClickListener(v -> {
float current = dataBoard.getCurrentValue();
if (current < dataBoard.getMaxValue()) {
dataBoard.setCurrentValue(current + 10);
seekBar.setProgress((int) dataBoard.getCurrentValue());
}
});
btnDecrease.setOnClickListener(v -> {
float current = dataBoard.getCurrentValue();
if (current > 0) {
dataBoard.setCurrentValue(current - 10);
seekBar.setProgress((int) dataBoard.getCurrentValue());
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
dataBoard.setCurrentValue(progress);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
}
3. acivitiy_main.xml代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:background="#FFFFFF"
tools:context=".MainActivity">
<com.example.dashboard.DataBoard
android:id="@+id/dataBoard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#FFFFFF"
app:db_outerDiameter="180dp"
app:db_ringWidth="20dp"
app:db_ringBaseColor="#E0E0E0"
app:db_ringDataColor="#2196F3"
app:db_textColor="#333333"
app:db_textSize="18sp"
app:db_maxValue="100"
app:db_currentValue="75"
app:db_innerStartColor="#FFFFFF"
app:db_innerEndColor="#E0E0E0"
app:db_outerStartColor="#BDBDBD"
app:db_outerEndColor="#616161" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp">
<Button
android:id="@+id/btnIncrease"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="增加"
/>
<Button
android:id="@+id/btnDecrease"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="减少"
/>
</LinearLayout>
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:max="100" />
</LinearLayout>
4. attrs.xml代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DataBoard">
<!-- 圆环外圈直径 -->
<attr name="db_outerDiameter" format="dimension" />
<!-- 圆环宽度 -->
<attr name="db_ringWidth" format="dimension" />
<!-- 圆环基本颜色 -->
<attr name="db_ringBaseColor" format="color" />
<!-- 圆环数据颜色 -->
<attr name="db_ringDataColor" format="color" />
<!-- 中心文字颜色 -->
<attr name="db_textColor" format="color" />
<!-- 中心文字大小 -->
<attr name="db_textSize" format="dimension" />
<!-- 量程最大值 -->
<attr name="db_maxValue" format="float" />
<!-- 当前值 -->
<attr name="db_currentValue" format="float" />
<!-- 内圈渐变起始颜色 -->
<attr name="db_innerStartColor" format="color" />
<!-- 内圈渐变结束颜色 -->
<attr name="db_innerEndColor" format="color" />
<!-- 外圈渐变起始颜色 -->
<attr name="db_outerStartColor" format="color" />
<!-- 外圈渐变结束颜色 -->
<attr name="db_outerEndColor" format="color" />
</declare-styleable>
</resources>
5. colors.xml代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<!-- 仪表盘自定义颜色 -->
<color name="dialColor">#3F51B5</color>
<color name="needleColor">#FF4081</color>
<color name="textColor">#212121</color>
<color name="backgroundColor">#FFFFFF</color>
</resources>
三、效果演示
主活动中添加了圆环控件,使用按钮可以增加和减少圆环控件的显示。

Android自定义圆环控件开发
922

被折叠的 条评论
为什么被折叠?



