I want to draw an oval shape inside another oval shape, but the second one should be cut off when it reaches the border of the first one.
This is the desired result:
How can this be achieved?
I want to draw an oval shape inside another oval shape, but the second one should be cut off when it reaches the border of the first one.
As pskink said, you could use PorterDuffXfermode to implement this feature, here is an simple :
public class DrawView : View
{
public DrawView(Context context):base(context)
{
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
Paint paint = new Paint();
paint.SetARGB(255, 255, 0, 0);
RectF oval2 = new RectF(60, 100, 300, 200);
canvas.DrawOval(oval2, paint);
//PorterDuff.Mode.SrcAtop means Discards the source pixels that do not cover destination pixels. Draws remaining source pixels over destination pixels
paint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.SrcAtop));
paint.Color = Color.Black;
RectF oval3 = new RectF(110, 150, 350, 250);
canvas.DrawOval(oval3, paint);
this.SetLayerType(LayerType.Software, null);
paint.SetXfermode(null);
}
}
Effect :
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:
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:
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:
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:
int[] colors = {Color.RED, Color.BLUE};
float[] positions = {0,1};
SweepGradient gradient = new SweepGradient(100, 100, colors , positions);
Any idea how to solve this?
The solution for this is to set the position of BLUE. This is done like so:
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:
float[] positions = {0,Xf/360f};
So if X is 90, the gradient will place BLUE at 0.25 of the circle:
To add to Yoav's solution.
On my Galaxy Nexus 4.2 stock Android, the solution given doesn't work.
If the array doesn't contain a 0.0f and 1.0f, it appears to be ignored.
My final solution was:
int[] colors = {Color.RED, Color.BLUE, Color.RED};
float[] positions = {0, Xf/360f, 1};
five years later, but the right way is make 0.749f with 0.750f of the separate line, simple code is like:
val colors = intArrayOf(0xffff0000.toInt(), 0xff0000ff.toInt(), 0xffff0000.toInt(), 0xffff0000.toInt())
val positions = floatArrayOf(0.0f, 0.749f, 0.750f, 1.0f)
Using SweepGradient, you can pass null for positions (in case you want default gradient) and you can also rotate the gradient by setLocalMatrix
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val centerX = width.toFloat() / 2
val centerY = height.toFloat() / 2
val paint = Paint()
paint.isAntiAlias = true
val colors = intArrayOf(Color.RED, Color.BLUE)
val gradient = SweepGradient(centerX, centerY, colors, null) // null position
val matrix = Matrix()
matrix.postRotate(270f, centerX, centerY) // rotate
gradient.setLocalMatrix(matrix)
paint.shader = gradient
val radius = 400f
val oval = RectF(centerX - radius,centerY - radius,centerX + radius,centerY + radius)
canvas?.drawArc(oval, 0f, 360f, false, paint)
}
I'm trying to draw a half circle inside the ImageView but i can't control where draw it. The idea is to draw it inside another circle with another color using drawcircle (50, 50, 20, paint). This is the code i'm using:
<ImageView android:id="#+id/circle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10sp" />
Bitmap bmp = Bitmap.createBitmap(100, 70, Bitmap.Config.RGB_565);
ImageView circle = (ImageView) findViewById (R.id.circle);
Paint paint = new Paint();
paint.setColor(Color.RED);
Canvas canvas = new Canvas (bmp);
RectF rectf = new RectF (0, 0, 40, 40);
canvas.drawArc(rectf, 0, 180, true, paint);
Thanks.
I think the problem you are having is: you do not understand the two different representations that is used by Circle and Arc.
For Circle, you need to give it the x, y position of the center, and the radius.
but for the Arc, you need the 4 edges of the container.
so it should look something like this:
//setting for Circle
paint.setColor(Color.RED);
int xPosition=50;
int yPosition=50;
int size = 40;
canvas.drawCircle(xPosition, yPosition, size/2, paint);
//setting for Arc
paint.setColor(Color.YELLOW);
size = size * 8 / 10; // make the Arc smaller
xPosition=xPosition-size/2;
yPosition=yPosition-size/2;
RectF rectf = new RectF (xPosition, yPosition, xPosition+size, yPosition+size);
canvas.drawArc(rectf, 0+45, 180, true, paint);
I want to draw circle, which will be colored with two colors. One color from 0 to 180 degree, and second color for the rest. I have something like this:
private void drawCircle(Canvas c)
{
RectF oval = new RectF(20, 20, 100, 100);
c.drawArc(oval, 0, 180, false, getPaintWithColor(R.color.background));
c.drawArc(oval, 180, 360, false, getPaintWithColor(R.color.font_grey));
}
private Paint getPaintWithColor(int colorId){
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(4);
paint.setColor(getResources().getColor(colorId));
return paint;
}
But after this, arc is monocolored with font_grey color.
From Canvas documentation:
sweepAngle Sweep angle (in degrees) measured clockwise
If the sweep angle is >= 360, then the oval is drawn completely.
The sweepAngle parameter isn't the ending angle, it's the size of the angle in degrees. Your second arc is drawing a complete oval, since your angle is 360.
Try using 180 for the sweep angle.
Try this :
Shader gradient = new SweepGradient (0,getMeasuredHeight()/2, Color.RED, Color.WHITE);
lighted.setShader(gradient);
canvas.drawArc(rectf, -90, 360, false, lightRed);
The following code snippet draws a red rectangle:
RectF rectangle = new RectF(50, 100, 100, 50);
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRoundRect(rectangle, 0, 0, paint);
However if i change rx and ry both to a positive value, say 5, than nothing is shown. Any ideas?
Your rectangle definition is incorrect. The parameters of a RectF are left, top, right and bottom, not x, y, width and height. Try with 50, 100, 150, 150 for instance.