Android - 如何绘制基于弧的渐变

时间:2023-01-22 20:17:24

I am trying to create an arc (variable number of degrees) that gradually goes from one color to another. From example from blue to red:

Android  - 如何绘制基于弧的渐变

我正在尝试创建一个逐渐从一种颜色到另一种颜色的弧(可变度数)。例如从蓝色到红色:

This is my code:

这是我的代码:

SweepGradient shader = new SweepGradient(center.x, center.y, resources.getColor(R.color.startColor),resources.getColor(R.color.endColor));
Paint paint = new Paint()
paint.setStrokeWidth(1);
paint.setStrokeCap(Paint.Cap.FILL);
paint.setStyle(Paint.Style.FILL);
paint.setShader(shader);
canvas.drawArc(rectF, startAngle, sweepAngle, true, paint);

But the result is the entire arc is painted with the same color.

但结果是整个弧线涂上了相同的颜色。

Edit:
After more experimenting, I found out that the color spread is determined by the angle of the arc. If I draw an arc with a small angle, only the first color is displayed. The larger the angle, more colors are drawn. If the angle is small it seems that there is no gradient.
Here is an example. I am drawing 4 arcs - 90, 180, 270 and 360:

编辑:经过更多的实验,我发现颜色的扩散是由弧的角度决定的。如果我绘制一个小角度的圆弧,则只显示第一种颜色。角度越大,绘制的颜色越多。如果角度很小,似乎没有梯度。这是一个例子。我画了4个弧--90,180,270和360:

RectF rect1 = new RectF(50, 50, 150, 150);
Paint paint1 = new Paint();
paint1.setStrokeWidth(1);
paint1.setStrokeCap(Paint.Cap.SQUARE);
paint1.setStyle(Paint.Style.FILL);

SweepGradient gradient1 = new SweepGradient(100, 100,
        Color.RED, Color.BLUE);
paint1.setShader(gradient1);

canvas.drawArc(rect1, 0, 90, true, paint1);

RectF rect2 = new RectF(200, 50, 300, 150);
Paint paint2 = new Paint();
paint2.setStrokeWidth(1);
paint2.setStrokeCap(Paint.Cap.SQUARE);
paint2.setStyle(Paint.Style.FILL);

SweepGradient gradient2 = new SweepGradient(250, 100,
        Color.RED, Color.BLUE);
paint2.setShader(gradient2);

canvas.drawArc(rect2, 0, 180, true, paint2);

RectF rect3 = new RectF(50, 200, 150, 300);
Paint paint3 = new Paint();
paint3.setStrokeWidth(1);
paint3.setStrokeCap(Paint.Cap.SQUARE);
paint3.setStyle(Paint.Style.FILL);

SweepGradient gradient3 = new SweepGradient(100, 250,
        Color.RED, Color.BLUE);
paint3.setShader(gradient3);

canvas.drawArc(rect3, 0, 270, true, paint3);

RectF rect4 = new RectF(200, 200, 300, 300);
Paint paint4 = new Paint();
paint4.setStrokeWidth(1);
paint4.setStrokeCap(Paint.Cap.SQUARE);
paint4.setStyle(Paint.Style.FILL);

SweepGradient gradient4 = new SweepGradient(250, 250,
        Color.RED, Color.BLUE);
paint4.setShader(gradient4);

canvas.drawArc(rect4, 0, 360, true, paint4);

And here is the result:

这是结果:

Android  - 如何绘制基于弧的渐变

This is surprising because I'd expect the RED to be at the start of the arc, the BLUE at the end and enything between to be spread evenly regardless of angle.
I tried to space the colors manually using the positions parameter but the results were the same:

这是令人惊讶的,因为我期望RED处于弧线的起点,最后的BLUE和它们之间的均匀分布,无论角度如何。我尝试使用positions参数手动分隔颜色但结果是相同的:

int[] colors = {Color.RED, Color.BLUE};
float[] positions = {0,1};
SweepGradient gradient = new SweepGradient(100, 100, colors , positions);

Any idea how to solve this?

知道怎么解决这个问题吗?

3 个解决方案

#1


28  

The solution for this is to set the position of BLUE. This is done like so:

解决方案是设置BLUE的位置。这样做是这样的:

int[] colors = {Color.RED, Color.BLUE};
float[] positions = {0,1};
SweepGradient gradient = new SweepGradient(100, 100, colors , positions);

The problem here is that when setting the position of BLUE to '1' this does not mean that it will be positioned at the end of the drawn arc, but instead at the end of the circle of which the arc is part of. To solve this, BLUE position should take into account the number of degrees in the arc. So if I'm drawing an arc with X degrees, position will be set like so:

这里的问题是,当将BLUE的位置设置为'1'时,这并不意味着它将位于绘制弧的末端,而是位于弧所属的圆的末端。要解决这个问题,蓝色位置应考虑弧度的度数。因此,如果我绘制一个X度的弧,位置将设置如下:

float[] positions = {0,Xf/360f};

So if X is 90, the gradient will place BLUE at 0.25 of the circle:

因此,如果X为90,则渐变将蓝色置于圆的0.25处:

Android  - 如何绘制基于弧的渐变

#2


10  

To add to Yoav's solution.

添加到Yoav的解决方案。

On my Galaxy Nexus 4.2 stock Android, the solution given doesn't work.

在我的Galaxy Nexus 4.2股票Android上,给出的解决方案不起作用。

If the array doesn't contain a 0.0f and 1.0f, it appears to be ignored.

如果数组不包含0.0f和1.0f,则它似乎被忽略。

My final solution was:

我的最终解决方案是:

int[] colors = {Color.RED, Color.BLUE, Color.RED}; 
float[] positions = {0, Xf/360f, 1};

#3


1  

five years later, but the right way is make 0.749f with 0.750f of the separate line, simple code is like:

五年后,但正确的方法是使用0.750f的单独线制作0.749f,简单的代码如下:

    val colors = intArrayOf(0xffff0000.toInt(), 0xff0000ff.toInt(), 0xffff0000.toInt(), 0xffff0000.toInt())
    val positions = floatArrayOf(0.0f, 0.749f, 0.750f, 1.0f)

#1


28  

The solution for this is to set the position of BLUE. This is done like so:

解决方案是设置BLUE的位置。这样做是这样的:

int[] colors = {Color.RED, Color.BLUE};
float[] positions = {0,1};
SweepGradient gradient = new SweepGradient(100, 100, colors , positions);

The problem here is that when setting the position of BLUE to '1' this does not mean that it will be positioned at the end of the drawn arc, but instead at the end of the circle of which the arc is part of. To solve this, BLUE position should take into account the number of degrees in the arc. So if I'm drawing an arc with X degrees, position will be set like so:

这里的问题是,当将BLUE的位置设置为'1'时,这并不意味着它将位于绘制弧的末端,而是位于弧所属的圆的末端。要解决这个问题,蓝色位置应考虑弧度的度数。因此,如果我绘制一个X度的弧,位置将设置如下:

float[] positions = {0,Xf/360f};

So if X is 90, the gradient will place BLUE at 0.25 of the circle:

因此,如果X为90,则渐变将蓝色置于圆的0.25处:

Android  - 如何绘制基于弧的渐变

#2


10  

To add to Yoav's solution.

添加到Yoav的解决方案。

On my Galaxy Nexus 4.2 stock Android, the solution given doesn't work.

在我的Galaxy Nexus 4.2股票Android上,给出的解决方案不起作用。

If the array doesn't contain a 0.0f and 1.0f, it appears to be ignored.

如果数组不包含0.0f和1.0f,则它似乎被忽略。

My final solution was:

我的最终解决方案是:

int[] colors = {Color.RED, Color.BLUE, Color.RED}; 
float[] positions = {0, Xf/360f, 1};

#3


1  

five years later, but the right way is make 0.749f with 0.750f of the separate line, simple code is like:

五年后,但正确的方法是使用0.750f的单独线制作0.749f,简单的代码如下:

    val colors = intArrayOf(0xffff0000.toInt(), 0xff0000ff.toInt(), 0xffff0000.toInt(), 0xffff0000.toInt())
    val positions = floatArrayOf(0.0f, 0.749f, 0.750f, 1.0f)