Am drawing a simple circle in a Canvas on Android.
Now I need to fill it with some gradient colors, but they are no really smooth.
This its what i have done:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
rectF.set(20, 20, this.get_Width() - this.get_Width()/10, this.get_Width() - this.get_Width()/10);
RadialGradient gradient = new RadialGradient(200, 200, 200, 0xFFFFFFFF,
0xFF000000, android.graphics.Shader.TileMode.CLAMP);
Paint mPaint = new Paint();
mPaint.setDither(true);
mPaint.setShader(gradient);
canvas.drawCircle(getWidth()/2, getHeight()/2, getWidth()/3, getGradient());
invalidate();
}
And this is the result:
My question is: Is it there some way to make HQ radial gradients?
Try adding the following to your Activity which contains the View that does the drawing:
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
Window window = getWindow();
// Eliminates color banding
window.setFormat(PixelFormat.RGBA_8888);
}
Finally I should initialize my Paint object as:
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
That makes the borders cleaner.
And with the #Waqas answer, make the colors itself smoothers.
Related
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 :
Hello i added rectangle in my canvas now i want to add textview or some other view in that rectangle.Suggest me some tutorial also. Thanks in advance
public class DrawView extends View {
public DrawView(Context context) {
super(context);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect rect = new Rect();
rect.set(20 ,10 ,canvas.getWidth()/2, canvas.getHeight()/2);
Paint paint = new Paint();
paint.setColor(Color.GREEN);
canvas.drawRect(rect, paint);
}
}
You can draw text on your canvas.
Paint mpaint= new Paint();
mpaint.setColor(Color.RED);//set red color for rectangle
mpaint.setStyle(Paint.Style.FILL);//mpaint will fill the rectangle
Paint paint2 = new Paint();
paint2.setColor(Color.GREEN);//green color for text
paint2.setTextSize(30f);//set text size. you can change the stroke width also
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawRect(30, 30, 600, 600, mpaint);
canvas.drawText("hello", 150, 150, paint2);//change x and y according to your needs
}
Resulting snapshot on samsung galaxy s3
Adding a View of any kind is out of question here since you are simply drawing on a canvas. But Canvas.drawText(...) might be exactly what you are looking for.
Is there any way in Android to draw a filled rectangle with say a black border. My problem is that the canvas.draw() takes one paint object, and to my knowledge the paint object can't have a different color for the fill and the stroke. Is there a way around this?
Try paint.setStyle(Paint.Style.FILL) and paint.setStyle(Paint.Style.STROKE).
Paint paint = new Paint();
Rect r = new Rect(10, 10, 200, 100);
#Override
public void onDraw(Canvas canvas) {
// fill
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.MAGENTA);
canvas.drawRect(r, paint);
// border
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
canvas.drawRect(r, paint);
}
If you are drawing multiple views then you could also use two paints, one for the stroke and one for the fill. That way you don't have to keep resetting them.
Paint fillPaint = new Paint();
Paint strokePaint = new Paint();
RectF r = new RectF(30, 30, 1000, 500);
void initPaints() {
// fill
fillPaint.setStyle(Paint.Style.FILL);
fillPaint.setColor(Color.YELLOW);
// stroke
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setColor(Color.BLACK);
strokePaint.setStrokeWidth(10);
}
#Override
protected void onDraw(Canvas canvas) {
// First rectangle
canvas.drawRect(r, fillPaint); // fill
canvas.drawRect(r, strokePaint); // stroke
canvas.translate(0, 600);
// Second rectangle
int cornerRadius = 50;
canvas.drawRoundRect(r, cornerRadius, cornerRadius, fillPaint); // fill
canvas.drawRoundRect(r, cornerRadius, cornerRadius, strokePaint); // stroke
}
You draw a rectangle with the color of the border and the size of the rectangle plus the border, you change the color of the paint and draw again the rectangle with the normal size.
I'm overriding Android's ImageView in order to make the corners of my image transparent. I can accomplish that clipping the canvas in my onDraw(Canvas canvas):
#Override
protected void onDraw(Canvas canvas) {
Path clipPath = new Path();
int w = this.getWidth();
int h = this.getHeight();
clipPath.addRoundRect(new RectF(0,0,w,h), 10.0f, 10.0f, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
}
Unfortunately, it's not possible to antialias this round rectangle, and the result are ugly corners like this:
I know I can clear parts of my canvas with antialiasing using Paint and PorterDuff.Mode.CLEAR, what I don't know is to specify the round corners as the region to be erased. I'm looking for something like this:
#Override
protected void onDraw(Canvas canvas) {
//superclass will draw the bitmap accordingly
super.onDraw(canvas);
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//this will erase a round rectangle, I need the exact inverse
canvas.drawRoundRect(rect, rx, ry, paint);
}
Is there any way to "erase" not the round rectangle, but it's inverse, ie, the round corners? And what if I just want to erase one of the corners?
Draw using a BitmapShader with a transparent color for your Paint object.
If you just want to erase one of the corners, try drawing it as a Path instead of a RoundRect.
protected void onDraw(Canvas canvas) {
BitmapShader bitmapShader = new BitmapShader(<original drawable>, TileMode.CLAMP, TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(0xFF000000);
paint.setShader(bitmapShader);
canvas.drawRoundRect(rect, rx, ry, paint);
}
Given a closed Path object result is like this:
Although that is a rectangle I'm looking for something which works with any closed Path.
While steelbytes' answer will probably give you more control over the individual sections of the gradient, you can do it without the path:
Paint m_Paint = new Paint();
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// start at 0,0 and go to 0,max to use a vertical
// gradient the full height of the screen.
m_Paint.setShader(new LinearGradient(0, 0, 0, getHeight(), Color.BLACK, Color.WHITE, Shader.TileMode.MIRROR));
canvas.drawPaint(m_Paint);
}
this may help.
Note: it's not efficient to create the Paint etc in every call to onDraw. This is just an demonstration of LinearGradient shader
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
int w = getWidth();
int h = getHeight();
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
Path pth = new Path();
pth.moveTo(w*0.27f,0);
pth.lineTo(w*0.73f,0);
pth.lineTo(w*0.92f,h);
pth.lineTo(w*0.08f,h);
pth.lineTo(w*0.27f,0);
p.setColor(0xff800000);
p.setShader(new LinearGradient(0,0,0,h,0xff000000,0xffffffff,Shader.TileMode.CLAMP));
canvas.drawPath(pth,p);
}