I have the following code to delimit the area of a view to be drawn:
Rect rect = new Rect();
rect.set(0, 0, 100, 100);
View.setClipBounds(rect);
This will draw my view only on the specified rectangle (or square, in this case). However, I wanted the view to be clipped to a circle. Is there any way to somehow round the corners of a Rect object?
In this case, you've to subclass that view and add some extra logic to it.
Add these codes to its constructor method, or wherever you would like to initialize the view.
final Path path = new Path();
path.addRoundRect(new RectF(0,0,getWidth(),getHeight()),10,10,Direction.CW);
Using these codes, you're defining a path along which your view is going to be drawn (the area inside the boundaries of the patch).
Add this method to the class to apply this mask on your view.
#Override
protected void dispatchDraw(Canvas canvas){
canvas.clipPath(path);
super.dispatchDraw(canvas);
}
Credits: https://stackoverflow.com/a/7559233/1841194
Try to use
RectF r = new RectF(10,100,200,400);
canvas.drawRoundRect(r, 0, 0, mPaint);
about
or square case of it.
The other approach is to use clipping mask. The concept of this idea is to use PorterDuffXfermode or PorterDuff .
This is an example for the rounded corner view. I don't know what directly you want that's why I just can give to base methods I've used. The other example.
Try this:
val circlePath = Path().apply {
addCircle(x, y, radius, Path.Direction.CW)
}
canvas.clipPath(circlePath)
Related
I'm trying to make a drop shadow blur effect WITH COLOR on a rectangular layout view. I've tried to use this code but to no avail.
int glowRadius = 14;
int glowColor = Color.parseColor("#acc5fe");
Paint paint = new Paint();
paint.setColor(glowColor);
paint.setMaskFilter(new BlurMaskFilter(glowRadius, BlurMaskFilter.Blur.OUTER));
RectF rectF = new RectF(mRootView.getHeight(), mRootView.getWidth(),
mRootView.getHeight(), mRootView.getWidth());
Canvas canvas = new Canvas();
canvas.drawRect(rectF, paint);
mRootView.draw(canvas);
It doesn't seem to do anything though.
I also tried to use shadowDx and shadowDy etc. but that does nothing.
How to add a blurred drop shadow to a button? is a very similar question but I don't think the 9-patch is a viable solution since it's a layout and not an image.
How do you create a drop outer shadow blur effect on Android?
Update
Still haven't found a successful answer. I want something like
where the shadow effect is on the email edittext with a different color than black.
try following A library for supporting convex material shadows
https://github.com/harjot-oberai/MaterialShadows
What I understand from your question is first you want to drop a shadow. Here is what you can do to drop a shadow.
Just add this to your parent layout in xml.
android:background="#android:drawable/dialog_holo_light_frame"
Check this answer for more information.
how to add shadow effect in alert dialog box in android
Let me know if this works for you.
Edit:
Please check this answer. This might help you.
Extending Android View class to add a dropshadow
It can be achieved using NinePatchDrawable. Below is a simple example.
protected NinePatchDrawable bg;
protected Paint paint;
protected Rect padding = new Rect();
protected Bitmap bmp;
protected void init() {
// decode the 9patch drawable
bg = (NinePatchDrawable) getResources().getDrawable(R.drawable.balloon);
// get paddings from the 9patch and apply them to the View
bg.getPadding(padding);
setPadding(padding.left, padding.top, padding.right, padding.bottom);
// prepare the Paint to use below
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.rgb(255,255,255));
paint.setStyle(Style.FILL);
// this check is needed in order to get this code
// working if target SDK>=11
if( Build.VERSION.SDK_INT >= 11 )
setLayerType(View.LAYER_TYPE_SOFTWARE, paint);
// set the shadowLayer
paint.setShadowLayer(
padding.left * .2f, // radius
0f, // blurX
padding.left * .1f, // blurY
Color.argb(128, 0, 0, 0) // shadow color
);
}
Also please try this color:
Color.argb(128, 0, 0, 0)
I am using a Drag and Drop event, and I want to change the drag shadow's opacity. I extended View.DragShadowBuilder class but I'm not able to set drag shadow's opacity. By default, it's semi transparent. I want it to look solid with no transparency. I do this:
#Override
public void onDrawShadow(Canvas canvas) {
ImageView ivPiece = (ImageView) getView();
BitmapDrawable drawable = (BitmapDrawable) ivPiece.getDrawable();
Bitmap piece = drawable.getBitmap();
Paint paint = new Paint();
paint.setAlpha(255);
paint.setAntiAlias(true);
canvas.drawBitmap(piece, 0, 0, paint);
}
But it doesn't work.
It appears that this isn't possible directly. However, an answer to a similar question gives a work-around, using a drag container. Hopefully that is helpful to you!
I need to make a thumbnail view with rounded corners and inner shadow. Usually I'm making ImageView frames with 9patches, which have served me well so far, but this time the effect I need requires drawing the inner shadow on top of the image (and not just around it). This lead me to extend the ImageView class and override the onDraw() method.
public class ThumbnailImageView extends ImageView {
After many tutorials (thanks StackOverflow!), I ended up with this code for the onDraw() method:
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
int radius = 4;
int padding = 2;
int bleed = 2;
RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xFF000000);
canvas.drawRoundRect(frame, radius, radius, mPaint);
Shader bitmapShader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xFF000000);
mPaint.setMaskFilter(new BlurMaskFilter(bleed, Blur.INNER));
mPaint.setShader(bitmapShader);
canvas.drawRoundRect(frame, radius, radius, mPaint);
}
What I'm basically doing, is drawing a black rounded rectangle first and then drawing a rounded-corners bitmap with fading edges (with the BlurMaskFilter) on top of it. The result is what I want:
The mBitmap value is initialized in the ImageView constructor like this:
mDrawable = getDrawable();
if (mDrawable != null) {
mBitmap = ((BitmapDrawable) mDrawable).getBitmap();
}
The problem is that I am overriding onDraw() completely (no super.onDraw()) is called, so I have to pre-scale all images to the desired thumbnail size (e.g. 96x96) or else only the top-left corner of the image is drawn. What I want to be able to do is take advantage of all the scaling the framework is doing when I assign the following xml values to the ThumbnailImageView:
android:id="#+id/thumb"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
To do this, I thought I should somehow call super.onDraw() while getting the effects I need at the same time. I have managed to get the rounded rectange by adding a clipping path to the canvas, but I can't find a way to add the inner shadow. This is the new onDraw() code:
#Override
protected void onDraw(Canvas canvas) {
int radius = 4;
int padding = 4;
RectF frame = new RectF(padding, padding, getWidth() - padding, getHeight() - padding);
Path clipPath = new Path();
clipPath.addRoundRect(frame, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);
super.onDraw(canvas);
// add inner shadow
}
I can see two alternatives:
1) To properly pre-scale the ImageView's bitmap. But where is the best place to do it? In it's constructor? In the onDraw() method where the framework seems to be doing it? Is the framework even resizing any bitmap or is there another way to draw a scaled image on the canvas without being bad for performance?
2) To add the inner shadow layer on top of what the super.onDraw() is drawing so far, but I'm running out of ideas on how to do this.
Any help would be appreciated.
Thanks!
Take a look at Eric's (from squareup) presentation material from Oreilly's AndoridOpen Conference last year in his lecture titled Beautiful Android
It has a ton of info that should help you out.
I wish they had the video of his presentation somewhere. I could not find it. So sorry.
EDIT : Thanks to #mykola for the yt link
I'm writing a canvas app on android and I'm looking to add shadows, but I've noticed a great slow-down when I add them to my paint object. My code is simple it looks like this:
...
Paint paint = new Paint();
paint.setShadowLayer(8.f, 0, 0, 0xff000000); // this line makes terribly slow drawing
canvas.drawRect(left, top, right, bottom, paint);
How can I make this faster?
While digging around to find a way to speed up my large text shadows, I stumbled on this question and answer:
setShadowLayer Android API differences
By using:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
I drastically sped up all the text shadows in my app.
Here is a sample of how I use it:
/**
* Set a backlight (shadow) on the passed TextView.
* #param textView
*/
void setBacklight(TextView textView) {
if (textView != null) {
float textSize = textView.getTextSize();
textView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
textView.setShadowLayer(textSize,0,0,getColor(R.color.color_backlight));
}
}
According to this doc:
https://developer.android.com/guide/topics/graphics/hardware-accel.html
It says that you can disable hardware acceleration for the view.
I don't know why, but somehow this magically speeds up my TextView shadow layers.
I know, I know. That method doesn't exist for the Canvas or Paint classes. So to answer the specific question (so I don't get blasted by everyone...), you could set that on the View that you intend to draw the canvas. Like this:
void inTheShadows(View view) {
float left = 0f;
float top = 0f;
float right = 10f;
float bottom = 10f;
Canvas canvas = new Canvas();
Paint paint = new Paint();
paint.setShadowLayer(8.f, 0, 0, 0xff000000);
canvas.drawRect(left, top, right, bottom, paint);
view.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
view.onDrawForeground(canvas);
}
You can achieve almost the same result using this code instead:
mPaint.setMaskFilter(new BlurMaskFilter(20, BlurMaskFilter.Blur.OUTER));
Use an image icon instead of drawing it :)
Yes shadowing is costly.
I want to fill the area outside a rectangle on a canvas. I use
canvas.drawRect(pTopLeft.x, pTopLeft.y, pBotRight.x, pBotRight.y, paint);
to draw the rectangle, but can't figure out how to fill outside the rectangle/clip.
Thanks
Geoff
Thanks ted and trojanfoe - the neatest solution I've come up with is
Point pTopLeft = new Point();
Point pBotRight = new Point();
//TODO:set x,y for points
Rect rHole = new Rect(pTopLeft.x, pTopLeft.y, pBotRight.x, pBotRight.y);
//assume current clip is full canvas
//put a hole in the current clip
canvas.clipRect(rHole, Region.Op.DIFFERENCE);
//fill with semi-transparent red
canvas.drawARGB(50, 255, 0, 0);
//restore full canvas clip for any subsequent operations
canvas.clipRect(new Rect(0, 0, canvas.getWidth(), canvas.getHeight())
, Region.Op.REPLACE);
You aren't going to fill outside the clip; that's the kind of thing clip is there to prevent! If you want to fill the space outside a rect and inside the drawing layer bounds, construct four auxiliary rects:
Rect above = new Rect(0, 0, canvas.getWidth(), pTopLeft.y);
Rect left = new Rect(0, pTopLeft.y, pTopLeft.x, pBotRight.y);
Rect right = new Rect(pBotRight.x, pTopLeft.y, canvas.getWidth(), pBotRight.y);
Rect bottom = new Rect(0, pBotRight.y, canvas.getWidth(), canvas.getHeight());
Then fill these.
ICS and above ...
canvas.clipRect(rHole, Region.Op.DIFFERENCE);
XOR, Difference and ReverseDifference clip modes are
ignored by ICS if hardware acceleration is enabled.
Just disable 2D hardware acceleration in your view:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Reference Android: Howto use clipRect in API15
You can't draw outside of the Canvas; that area belongs to the parent View. Do you have the ability to subclass the parent View and do your drawing in that class instead?
If you want to draw outside of the Canvas clip then you'll have to invalidate() the areas you are interested in.