在圆弧上画一个圆形的空心拇指

我想创build一个圆形的图表,将显示我的应用程序的值的范围。 这些值可以分为3类:低,中,高 – 分别由3种颜色表示:蓝色,绿色和红色(分别)。

在这个范围之上,我想要显示实际测量值 – 在相关范围部分上以“拇指”的forms:

见附图

根据测量值,白色拇指在范围弧上的位置可能会改变。

目前,我可以通过在视图的onDraw方法内的同一中心绘制3个弧来绘制3色的范围:

width = (float) getWidth(); height = (float) getHeight(); float radius; if (width > height) { radius = height / 3; } else { radius = width / 3; } paint.setAntiAlias(true); paint.setStrokeWidth(arcLineWidth); paint.setStrokeCap(Paint.Cap.ROUND); paint.setStyle(Paint.Style.STROKE); center_x = width / 2; center_y = height / 1.6f; left = center_x - radius; float top = center_y - radius; right = center_x + radius; float bottom = center_y + radius; oval.set(left, top, right, bottom); //blue arc paint.setColor(colorLow); canvas.drawArc(oval, 135, 55, false, paint); //red arc paint.setColor(colorHigh); canvas.drawArc(oval, 350, 55, false, paint); //green arc paint.setColor(colorNormal); canvas.drawArc(oval, 190, 160, false, paint); 

这是结果弧:

目前的电弧

我的问题是,我如何:

  1. 在这三种颜色之间创build一个平滑的渐变 (我尝试使用SweepGradient但它没有给我正确的结果)。
  2. 如图所示创build覆盖白色的拇指 ,这样我就可以控制在哪里显示它。

  3. 在我的范围弧上animation这个白色的拇指。

注意:三色的范围是静态的 – 所以另一个解决scheme可以是只需要绘制画笔,然后画白色的拇指就可以了(所以我可以听到这样的解决scheme:)

Solutions Collecting From Web of "在圆弧上画一个圆形的空心拇指"

我会用你的头两个问题的面具。

1.创build一个平滑的渐变

第一步将绘制两个线性渐变的矩形。 第一个矩形包含蓝色和绿色,第二个矩形包含绿色和红色,如下图所示。 我标记了两个矩形相互接触的线,以澄清它们实际上是两个不同的矩形。

第一步

这可以使用下面的代码(摘录)来实现:

 // Both color gradients private Shader shader1 = new LinearGradient(0, 400, 0, 500, Color.rgb(59, 242, 174), Color.rgb(101, 172, 242), Shader.TileMode.CLAMP); private Shader shader2 = new LinearGradient(0, 400, 0, 500, Color.rgb(59, 242, 174), Color.rgb(255, 31, 101), Shader.TileMode.CLAMP); private Paint paint = new Paint(); // ... @Override protected void onDraw(Canvas canvas) { float width = 800; float height = 800; float radius = width / 3; // Arc Image Bitmap.Config conf = Bitmap.Config.ARGB_8888; // See other config types Bitmap mImage = Bitmap.createBitmap(800, 800, conf); // This creates a mutable bitmap Canvas imageCanvas = new Canvas(mImage); // Draw both rectangles paint.setShader(shader1); imageCanvas.drawRect(0, 0, 400, 800, paint); paint.setShader(shader2); imageCanvas.drawRect(400, 0, 800, 800, paint); // /Arc Image // Draw the rectangle image canvas.save(); canvas.drawBitmap(mImage, 0, 0, null); canvas.restore(); } 

因为你的目标是有一个圆顶的彩色圆弧,我们接下来需要定义两个矩形的区域,这些矩形应该是用户可见的。 这意味着两个矩形中的大部分都被掩盖掉了,因此不可见。 相反唯一需要保留的是弧形区域。

结果应该是这样的:

第二步

为了实现所需的行为,我们定义了一个只显示矩形内的弧区域的掩码。 为此,我们大量使用PaintsetXfermode方法。 作为参数,我们使用PorterDuffXfermode不同实例。

 private Paint maskPaint; private Paint imagePaint; // ... // To be called within all constructors private void init() { // I encourage you to research what this does in detail for a better understanding maskPaint = new Paint(); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); imagePaint = new Paint(); imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); } @Override protected void onDraw(Canvas canvas) { // @step1 // Mask Bitmap mMask = Bitmap.createBitmap(800, 800, conf); Canvas maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setShader(null); paint.setStrokeWidth(70); paint.setStyle(Paint.Style.STROKE); paint.setStrokeCap(Paint.Cap.ROUND); paint.setAntiAlias(true); final RectF oval = new RectF(); center_x = 400; center_y = 400; oval.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawArc(oval, 135, 270, false, paint); // /Mask canvas.save(); // This is new compared to step 1 canvas.drawBitmap(mMask, 0, 0, maskPaint); canvas.drawBitmap(mImage, 0, 0, imagePaint); // Notice the imagePaint instead of null canvas.restore(); } 

2.创build覆盖白色拇指

这解决了你的第一个问题。 第二个可以使用口罩再次实现,虽然这次我们想要实现不同的东西。 之前,我们只想显示背景图像的特定区域(圆弧)(两个矩形)。 这一次我们想要做相反的事情:我们定义一个背景图像(大拇指),并掩盖其内在的内容,以便只有笔画似乎依然存在。 应用于弧形图像的拇指覆盖彩色弧与透明的内容区域。

所以第一步就是画拇指。 我们使用与背景圆弧半径相同但angular度不同的圆弧,从而产生更小的圆弧。 但是因为拇指应该“围绕”背景弧线,所以其笔触宽度必须大于背景弧线。

 @Override protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image mImage = Bitmap.createBitmap(800, 800, conf); imageCanvas = new Canvas(mImage); paint.setColor(Color.WHITE); paint.setStrokeWidth(120); final RectF oval2 = new RectF(); center_x = 400; center_y = 400; oval2.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); imageCanvas.drawArc(oval2, 270, 45, false, paint); // /Thumb Image canvas.save(); canvas.drawBitmap(RotateBitmap(mImage, 90f), 0, 0, null); canvas.restore(); } public static Bitmap RotateBitmap(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } 

代码的结果如下所示。

第三步

所以,现在我们有一个覆盖背景弧的拇指,我们需要定义去除拇指内部的掩码,以便背景弧再次变为可见。

为了达到这个目的,我们基本上使用与之前相同的参数来创build另一个弧线,但这次笔触宽度必须与用于背景弧线的宽度相同,因为这标记了我们想要在拇指内移除的区域。

使用下面的代码,结果图像如图4所示。

第四步

 @Override protected void onDraw(Canvas canvas) { // @step1 // @step2 // Thumb Image // ... // /Thumb Image // Thumb Mask mMask = Bitmap.createBitmap(800, 800, conf); maskCanvas = new Canvas(mMask); paint.setColor(Color.WHITE); paint.setStrokeWidth(70); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); final RectF oval3 = new RectF(); center_x = 400; center_y = 400; oval3.set(center_x - radius, center_y - radius, center_x + radius, center_y + radius); maskCanvas.drawBitmap(mImage, 0, 0, null); maskCanvas.drawArc(oval3, 270, 45, false, paint); // /Thumb Mask canvas.save(); canvas.drawBitmap(RotateBitmap(mMask, 90f), 0, 0, null); // Notice mImage changed to mMask canvas.restore(); } 

3.animation白色的拇指

你问题的最后一部分将是animation弧的运动。 我没有固定的解决scheme,但也许可以引导你在一个有用的方向。 我会尝试以下内容:

首先将拇指定义为一个ImageView ,它是整个弧形图的一部分。 更改graphics的选定值时,可以围绕背景弧的中心旋转缩略图。 因为我们想要animation的animation,只是设置拇指图像的旋转将是不够的。 相反,我们使用类似这样的RotateAnimation

 final RotateAnimation animRotate = new RotateAnimation(0.0f, -90.0f, // You have to replace these values with your calculated angles RotateAnimation.RELATIVE_TO_SELF, // This may be a tricky part. You probably have to change this to RELATIVE_TO_PARENT 0.5f, // x pivot RotateAnimation.RELATIVE_TO_SELF, 0.5f); // y pivot animRotate.setDuration(1500); animRotate.setFillAfter(true); animSet.addAnimation(animRotate); thumbView.startAnimation(animSet); 

这远不是我想要的最终结果,但它可以帮助您寻找所需的解决scheme。 这是非常重要的,你的枢轴值必须引用你的背景弧的中心,因为这是你的拇指图像应该旋转的点。

我已经testing了我的(完整)代码API级别16和22,23,所以我希望这个答案至less给你如何解决你的问题的新思路。

请注意,在onDraw方法中的分配操作是一个坏主意,应该避免。 为了简单,我没有按照这个build议。 此外,代码将被用作正确方向的指导,而不是简单地复制和粘贴,因为它使用了大量的幻数,并且通常不遵循良好的编码标准。

  1. 我会通过查看原始devise来改变绘制视图的方式,而不是绘制3个大写字母,而只画出1行,这样SweepGradient就可以工作。

  2. 这个迁徙有点棘手,你有两个select:

    • 创build一个4弧的Path
    • 画出2个弧 – 一个是大白(填充白色,所以你仍然想使用Paint.Style.STROKE )和另一个顶部,使其填充透明,你可以用PorterDuff xfermode实现它,它可能会带你几个尝试,直到你没有清除绿色圆圈。
  3. 我想你想要animation的拇指位置,所以只需使用简单的Animation ,使视图无效,并相应地绘制拇指视图位置。

希望这有助于