I'm trying to draw a ring with black shadow border. I'm able to achieve this with custom view when I use any color like RED, but what I want is a transparent circle with black shadow border.
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setShadowLayer(5.5f, 6.0f, 6.0f, Color.BLACK);
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(70, 70, 50, mPaint); }
What's happening here is that it's drawing a filled in transparent circle, and setting the shadow layer to that. Since the circle is transparent, you see the whole shadow of the object through it, not just the edges you're looking for. The shadow is black, so it looks like the whole circle is black.
Try setting the Paint style to Stroke. That should leave the middle transparent, and just draw the shadow of the outer ring. It may draw the shadow in both directions, though(inner and outer), so you may have to adjust the shadow radius accordingly.
mPaint.setStyle(Paint.Style.STROKE);
Are you targeting Android SDK 11 or higher? Since HoneyComb shadow rendring with hardware support had been disabled, you habe to turn on software rendering for this layer. You have to annotate your function for setting up the paint like this:
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setUpPaint(){
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setShadowLayer(5.5f, 6.0f, 6.0f, 0x80000000);
/* --- for android:minSdkVersion="11" --- */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(LAYER_TYPE_SOFTWARE, mPaint);
}
}
You'll need to effectively draw the shadow using a fully transparent colour, as you've found so far, then remove that coloured center using PorterDuff.Mode.CLEAR - leaving just the shadow on the outside.
PorterDuffXfermode mXferMode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
// draw the src/dst example into our offscreen bitmap
int sc = canvas.saveLayer(0, 0, 70 + 50, 70 + 50, null,
Canvas.MATRIX_SAVE_FLAG |
Canvas.CLIP_SAVE_FLAG |
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
Canvas.CLIP_TO_LAYER_SAVE_FLAG);
canvas.drawCircle(70, 70, 50, shadowPaint);
shadowPaint.setXfermode(mXferMode);
canvas.drawCircle(70, 70, 50, shadowPaint);
shadowPaint.setXfermode(null);
canvas.restoreToCount(sc);
Related
I'm using a simple custom view which draw a path and clip its children.
Code used :
private void config() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setShadowLayer(10.0f, 4.0f, 4.0f, DARK)
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(20);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
circlePath.reset();
circlePath.addCircle(cx, cy, circleRadius, Path.Direction.CW);
canvas.drawPath(circlePath, paint);
canvas.clipPath(circlePath);
super.dispatchDraw(canvas);
canvas.restore();
}
The path is fully transparent with only a white stroke. If there is no child inside this view container everything is fine.
Empty path :
Problem : I have noticed when a child is clipped, it seems that pixels appears around the white stroke, and only inside the path
Path with a black clipped children inside:
I zoomed and resized screenshots to better understand but also in real size pixels are visible.
I tried without shadowLayer but there is still pixels
Could someone tell me what is the problem source and how to fix it ?
I have drawn a circle filled with black color in the canvas and I have set the background color of the canvas to red.
I want only the circle which is black color to appear as my view but I get the red color as well.
I tried using canvas.clipPath() it dint work. I searched the net and found out we need to disable hardware acceleration to get it work. I tried that but it still dint work.
Tried disabling the Hardware Acceleration for particular view:
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
And also to whole application:
android:hardwareAccelerated="false"
Dint work in both the cases.
Any ideas on how to make it work ?
Code:
And here I am clipping
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
path.reset();
left = 50;
top = 50;
right = getWidth()- 50;
bottom = getHeight()-50;
RectF rectf = new RectF(left, top, right, bottom);
path.arcTo(rectf, startAngle, sweepAngle);
path.lineTo(linex, liney);
canvas.clipPath(path);
canvas.drawPath(path, paint);
//canvas.restore();
}
This is not what clip path is for. When you draw a path and then clip it - it means that the rest of the things you will draw on the canvas from that point will be masked by the path.
In your case you draw a red background before clipping the canvas - so it went all over the canvas, then you clipped it but draw only inside the path, so the clipping was useless.
you can get what you need that in that code:
// Do not set any background to the view before
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.canvas = canvas;
path.reset();
left = 50;
top = 50;
right = getWidth()- 50;
bottom = getHeight()-50;
RectF rectf = new RectF(left, top, right, bottom);
path.arcTo(rectf, startAngle, sweepAngle);
path.lineTo(linex, liney);
canvas.clipPath(path);
canvas.drawRect(0, 0, getWidth(), getHeight(), Red Paint in here);
canvas.drawPath(path, paint);
//canvas.restore();
}
That way you draw the background after pathClip
You will not see any red color because you draw all over the path right after it, if I am guessing right - you want to be able to draw a part of a circle in one color and the rest in other - you can achieve it if your path that you will clip will be the full circle and the path that you draw will be the part that you want to draw
I'm working with canvas im my application and I need to draw a circle.
To do that, I'm using the drawCicle(cx, cy, radious, paint) method for the canvas class.
The problem is that the circle's edges appear pixellated. And its kinf of oval.
This is my code:
public void drawCircle(){
Paint paint = new Paint();
paint.setColor(Color.rgb(52, 73, 94));
canvas.drawCircle(200, 300, 33, paint);
}
Use paint.setFlags(Paint.ANTI_ALIAS_FLAG)
This enables anti-aliasing => edges become smoother
My question in my opinion is basic.
However i don't find information about that and how i can do this.
It is possible split a textview? Put a line in the middle of the textview?
**TextView**
________________
| |
|________________|
| |
|________________|
Other thing.... Imagine that textview have height=100dip. It is possible color only the first 10% of textview? Color only the first 10dp??
Anyone can help?
Thank you four your time and help.
First, You can't split a TextView. But you can achieve by setting a right image as android:setDrawableBottom="yourImage"
You are able to customise a View in Android by overrideing the onDraw method of that View.
Something you might consider would be:
#Override
protected void onDraw(Canvas canvas) {
// paint a line through the centre
Paint paint = new Paint();
canvas.drawLine(0, canvas.getWidth(), canvas.getHeight()/2,
canvas.getHeight()/2, paint);
super.onDraw(canvas);
}
This would draw a line through the centre of the View (in your case a TextView). You could use the same method for your 10%/90% colouring.
Eg.
#Override
protected void onDraw(Canvas canvas) {
// paint a region blue
Paint paint = new Paint();
paint.setColor(Color.BLUE);//or whatever colour you want
canvas.drawRect(0, canvas.getHeight()/10, canvas.getWidth(),
canvas.getHeight(), paint)
super.onDraw(canvas);
}
Draw rect takes the arguments:
canvas.drawRect(left, top, right, bottom, paint)
And there are alternatives where you can pass in the actual drawing Rectangle etc.
I have a problem. I would like to have a textview with a gradient as color. And a black shadow behind it. The problem is that the shadow is using the color of the gradient in stead of using the called color (Color.BLACK)
My code is:
numberTextView = (TextView)findViewById(R.id.something);
Shader textShaderTop = new LinearGradient(0, 30, 0, 60,
new int[]{Color.parseColor("#A6A6A6"), Color.parseColor("#E8E8E8"), Color.parseColor("#A6A6A6")},
new float[]{0, 0.5f, 1}, TileMode.CLAMP);
numberTextView.getPaint().setShader(textShaderTop);
numberTextView.setShadowLayer(
0.1f, //float radius
20f, //float dx
20f, //float dy
Color.BLACK //this is not black on the screen, but it uses the gradient color!?
);
Does anybody knows what to do
I had exactly the same problem.
I managed to fix it by extending TextView and overriding onDraw method.
Here is how it looks like
#Override
protected void onDraw(Canvas canvas) {
// draw the shadow
getPaint().setShadowLayer(1, 1, 1, 0xbf000000); // or whatever shadow you use
getPaint().setShader(null);
super.onDraw(canvas);
// draw the gradient filled text
getPaint().clearShadowLayer();
getPaint().setShader(new LinearGradient(0, getHeight(), 0, 0, 0xffacacac, 0xffffffff, TileMode.CLAMP)); // or whatever gradient/shader you use
super.onDraw(canvas);
}
However this method probably won't work if you want to use colors with transparency in your gradient.
Thank you for sidon's answer. It helped me.
And I add this answer because I found a way to use colors with transparency in gradient.
So, please refer to sidon's answer first and upvote his one.
I found below at "setShadowLayer" Method Description from here.
The alpha of the shadow will be the paint's alpha if the shadow color is opaque, or the alpha from the shadow color if not.
So, point is shadowColor must be not opaque to use colors with transparency in gradient.
Here is code.
#Override
protected void onDraw(Canvas canvas) {
// draw the shadow
getPaint().setShader(null);
setTextColor(0x00ffffff); // set the paint's alpha by 00
getPaint().setShadowLayer(3.0f, 1.5f, 1.8f, shadowColor); // shadowColor must be not opaque
super.onDraw(canvas);
// draw the gradient filled text
getPaint().clearShadowLayer();
setTextColor(0xffffffff); // set the paint's alpha by ff
getPaint().setShader(new LinearGradient(0, 0, getWidth(), getHeight(), 0x7fff8809, 0x7f09ffff, Shader.TileMode.CLAMP)); // or whatever gradient/shader you use
super.onDraw(canvas);
}
If shadowColor is opaque, you may change it as not opaque by reduce the alpha by one.
if((shadowColor >>> 24) == 0xff)
shadowColor &= 0xfeffffff;
Thank you once again for sidon's answer.
2018-12-16 Edit:
If you have the same alpha value about colors, below code would better.
public class TextView_Gradient extends TextView {
public TextView_Gradient(Context context) {
super(context);
setTextColor(0x3fffffff); // set the paint's alpha by 3f
}
#Override
protected void onDraw(Canvas canvas) {
// draw the shadow
getPaint().setShader(null);
// shadowColor must be opaque.
getPaint().setShadowLayer(3.0f, 1.5f, 1.8f, shadowColor);
super.onDraw(canvas);
// draw the gradient filled text
getPaint().clearShadowLayer();
// gradient colors must be opaque, too.
getPaint().setShader(new LinearGradient(0, 0, getWidth(), getHeight(), 0xffff8809, 0xff09ffff, Shader.TileMode.CLAMP));
super.onDraw(canvas);
}
}
Because the alpha of the shadow will be the paint's alpha if the shadow color is opaque. And the alpha of the gradient colors is the paint's alpha if the alpha of the gradient colors are ff(opaque).
(Or the final alpha of text can be scaled again by the gradient color's alpha value provided that the paint's alpha is ff.)
Output: