Android 仪表盘View

导语

这里展示的View估计项目中多半是用不到的,只是用来加深理解的。文章末尾会有全部的代码,如果想研究可以复制过去直接运行,不需要额外的资源。

先看效果:
这里写图片描述
这里指针是通过手指来改变方向的,并不能通过数字参数来改变,如果需要,可以更改相应的代码。

需要的数学知识

理论的涉及也非常简单,如下所示:

  1. 在坐标系中,一个点与原点连线与X轴的正切值 tan = 点的纵坐标 ÷ 点的横坐标
  2. 在每一个象限中,正切函数是单调函数;如图所示:
    这里写图片描述

绘制流程

绘制由线段组成的圆弧

这里写图片描述

利用线段的旋转来绘图

绘制上图有多种方法,首先介绍一种简单的方法:
将线段旋转多个角度,这样可以绘制出一个圆弧型:

private int width;
private int height;

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.translate(width / 2, height / 2);
    Paint mPaint = new Paint();
    mPaint.setStrokeWidth(5);
    for (int i = 0; i <= 360; i += 5) {               // 绘制圆形之间的连接线
        canvas.drawLine(0, 120, 0, 200, mPaint);
        canvas.rotate(10);
    }
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    width = w;
    height = h;
}

上述代码的执行效果:
这里写图片描述
虽然丑了点,但可以说明问题。不过这样做,我们缺乏对弧形的控制。例如:如何实现圆弧呢?是不是要手动计算起始坐标,旋转的角度,扫过的角度等各种各样的问题?因为怕麻烦,这个方案就被我华丽的抛弃了。

利用两个同心圆来绘制

这里写图片描述

思路:

  1. 从圆心发射一条射线出来,与两个圆相交于点A和点B,链接A与B,就可以划出一条我们想要的线段。
  2. 均匀的发射多条射线,我们就可以得到一个由线段组成的圆弧。
  3. 如果两个圆圈是圆弧的话,就可以达到我们所要的效果

所以,最终确定的步骤为:

  1. 画一个大圆弧
  2. 画一个缩小版的小圆弧
  3. 均匀地在两个圆弧之间画线段

用动态图来展示下:

这里写图片描述
相关代码比较多,在文章末尾已经贴出来了(88-172行,代码中有后续的细节处理,需要甄别下相关的代码),这里只是写下思路,不再重复贴代码了

画个一个长度固定、原点确定,方向随着手指变化的指针

这里写图片描述
这步要实现的效果如上图所示

假设,之前的指针为OZ,现在我们用手指触摸了点A,这时我们希望指针变为OB,那么,该如何实现呢?

  1. 获取A点的坐标(通过onTouchEvent()可以获取到)
  2. 画取线段OA(O点为(0,0),所以可以画取)
  3. 通过测量OA,可以利用PathMeasure.getPosTan()来获取B点的坐标(指针的长度是固定的)
  4. 在Cavas中画OB线段
    这里写图片描述

如果我们触摸点为X,距离过短怎么办呢?

  1. 链接OX,并用MeasurePath来测量OX的长度,以及X的坐标(a,b)
  2. 计算OY与OX的比例 R = OY ÷ OX
  3. 计算Y点的坐标 x = a × R, y = b × R
  4. 在Cavas中画OY线段
    这里写图片描述
    相关代码同样比较多,在文章末尾已经贴出来了(179-242行,代码中有后续的细节处理,需要甄别下相关的代码),这里只是写下思路,不再重复贴代码了

处理越界的情况

这里写图片描述
上图情况是我们不想看到。如果指针偏到最右边,就不能再往下偏了;左边同理。这个时候,就需要想到tan函数的性质:

在每一个象限中,正切函数是单调函数

这里写图片描述

说明下:

  1. 在第二象限中,当前的tan值小于边界OA的tan值a时,说明此时是在边界外面;如果大于a,说明在边界里面
  2. 在第一象限中,当前的tan值大于OB的tan值b时,说明在边界外面;如果小于b,说明在边界里面
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要在Android上绘制仪表盘,可以使用Canvas和Paint对象来绘制。以下是一个简单的示例: 1. 创建一个自定义View类,例如DashboardView。 2. 在onDraw方法中,创建一个Canvas对象并使用Paint对象来绘制仪表盘。 3. 首先,绘制一个圆形的底部,使用Paint对象设置颜色和样式。 4. 绘制仪表盘的指针,根据当前数值计算指针的角度,然后使用Canvas的rotate方法旋转指针。 5. 最后,绘制仪表盘的刻度线和数字。可以使用Paint对象设置颜色,样式和文本大小。 以下是一个简单的示例代码: ```java public class DashboardView extends View { private Paint mPaint; private int mValue; private int mMaxValue; public DashboardView(Context context) { super(context); init(); } public DashboardView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public DashboardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(10); mPaint.setColor(Color.BLUE); } public void setValue(int value) { mValue = value; invalidate(); } public void setMaxValue(int maxValue) { mMaxValue = maxValue; invalidate(); } @Override protected 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; // 绘制底部圆形 mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.LTGRAY); canvas.drawCircle(centerX, centerY, radius, mPaint); // 绘制指针 mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.BLUE); int angle = mValue * 180 / mMaxValue; canvas.save(); canvas.rotate(angle, centerX, centerY); canvas.drawLine(centerX, centerY, centerX, centerY - radius, mPaint); canvas.restore(); // 绘制刻度线和数字 mPaint.setTextSize(40); for (int i = 0; i <= mMaxValue; i += 10) { int tickAngle = i * 180 / mMaxValue; canvas.save(); canvas.rotate(tickAngle, centerX, centerY); if (i % 20 == 0) { canvas.drawLine(centerX, centerY - radius, centerX, centerY - radius + 40, mPaint); canvas.drawText("" + i, centerX - mPaint.measureText("" + i) / 2, centerY - radius + 80, mPaint); } else { canvas.drawLine(centerX, centerY - radius, centerX, centerY - radius + 20, mPaint); } canvas.restore(); } } } ``` 可以在Activity中使用该自定义View类: ```java public class MainActivity extends AppCompatActivity { private DashboardView mDashboardView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDashboardView = findViewById(R.id.dashboard_view); mDashboardView.setMaxValue(100); } public void onButtonClick(View view) { int value = new Random().nextInt(101); mDashboardView.setValue(value); } } ``` 在布局文件中添加该自定义View: ```xml <com.example.dashboard.DashboardView android:id="@+id/dashboard_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 点击按钮可以随机设置数值。效果如下图所示: ![DashboardView](https://i.imgur.com/5c0K0JF.png)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值