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)
Related
background
I have a small circular contact photo view that I need to show the user.
If the photo is available, I should show it, while the image gets rounded to a circle, and has an elevation.
If the photo isn't available, I show an icon inside with a background, while still it's rounded and has elevation.
The problem
I've managed to make the photo showing work only on Android 5 and above:
But, it has a bad color around the edges as it tries to show the background of the FAB, and on Android 4.x and below it it showing as a simple rectangular content, with nothing that's related to FAB, probably because padding is what's protecting it for the shadow to be shown.
I also need to be able to add a stroke (a thin line of specific color around the rounded image), but I'm not sure how to add it.
What I've tried
This is in the layout file:
<android.support.design.widget.FloatingActionButton
android:id="#+id/image"
android:layout_width="#dimen/test"
android:layout_height="#dimen/test"/>
"test" is 80dp.
And this is in the code:
FloatingActionButton floatingActionButton = (FloatingActionButton) view.findViewById(R.id.image);
floatingActionButton.setPadding(0, 0, 0, 0);
final Bitmap bitmap = ...
RoundedCornersDrawable roundedCornersDrawable = new RoundedCornersDrawable(getResources(), bitmap, bitmap.getWidth() / 2);
floatingActionButton.setImageDrawable(roundedCornersDrawable);
code of RoundedCornersDrawable:
public class RoundedCornersDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
public RoundedCornersDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
super(resources, bitmap);
bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
final Bitmap b = getBitmap();
p = getPaint();
p.setAntiAlias(true);
p.setShader(bitmapShader);
final int w = b.getWidth(), h = b.getHeight();
rect = new RectF(0, 0, w, h);
this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
}
#Override
public void draw(final Canvas canvas) {
canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
}
}
The question
How do I get the FAB to work this way? How can I disable the padding at will, for all Android versions, and yet still have a rounded image with shadow ?
How do I also add a stroke to the rounded FAB ?
I think I was too fast in writing this post, while it seems there is already one about it here:
How to add a shadow and a border on circular imageView android?
I will have a look at it and see if it matches the requirements of what I need.
EDIT: it doesn't look as well as FAB (especially the shadow), plus I don't see the ability to put the small content in the center, like in FAB. It always puts the content in center-crop way.
Of course, I could just put a smaller sized image in it....
EDIT: I think I've found the right library this time:
https://github.com/lopspower/CircularImageView
It allows a shadow, customize the shadow size and color, and also a border, and also how to scale the image.
It's not quite a FAB, and it doesn't have the ability to put the image at the center without cropping, but it's enough for me.
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)
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!
So I tried the code from here: Creating an ImageView with a mask. I'm using the following images as original and mask:
However, the result I get is this:
Note that the window background is not black, but holo light (which on the galaxy nexus looks like a very pale gray, not completely white). The second image is the result I get when an item is selected on a list view.
If instead I create a new Bitmap using the same algorithm and then pass it to the image view instead of overriding onDraw(), it draws correctly:
Canvas canvas = new Canvas();
Bitmap mainImage = //get original image
Bitmap maskImage = //get mask image
Bitmap result = Bitmap.createBitmap(mainImage.getWidth(), mainImage.getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(result);
Paint paint = new Paint();
paint.setFilterBitmap(false);
canvas.drawBitmap(mainImage, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(maskImage, 0, 0, paint);
paint.setXfermode(null);
imageView.setImageBitmap(result);
I get the expected result:
Note the fade is correctly applied. This is more evident when a selection is made.
So what's going on on ImageView's onDraw method to create this black backdrop instead of letting the window background show through? What's interesting is that if the original image itself has some transparency, that transparency is respected, for example:
I can't figure it out by myself. I'd rather be able to do it on onDraw instead of pre-creating the bitmap because it only works for bitmaps as source and mask. I want to be able to do it with other drawables like gradients and solid colours but on those cases the width and height are not set.
I have found the perfect combination for creating masking without black border after researching through all the stackoverflow posts. It suits my purpose quite well.
Currently I'm creating a draggable view using one normal image and a masking image (a png with transparency), so I'll need to override the onDraw function.
private Bitmap mImage = ...;
private Bitmap mMask = ...; // png mask with transparency
private int mPosX = 0;
private int mPosY = 0;
private final Paint maskPaint;
private final Paint imagePaint;
public CustomView (final Context context) {
maskPaint = new Paint();
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
imagePaint = new Paint();
imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
}
/* TODO
if you have more constructors, make sure you initialize maskPaint and imagePaint
Declaring these as final means that all your constructors have to initialize them.
Failure to do so = your code won't compile.
*/
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.drawBitmap(mMask, 0, 0, maskPaint);
canvas.drawBitmap(mImage, mPosX, mPosY, imagePaint);
canvas.restore();
}
Answering my own question. The Xfermode was working as intended. The paint was making the resulting are of the canvas transparent (which was the canvas used by the window activity). Since the canvas itself was being set transparent, the window was showing what was behind it: the black background.
To do it properly, indeed a new Bitmap has to be created to hold the result of the alpha mask. I updated the code to take into account drawables of all types.
In this Code Apply:
mask_over = BitmapFactory.decodeResource(
getResources(), mask_over1[0]);
icon = Bitmap.createScaledBitmap(icon, screenwidth, screenwidth, false);
mask_over = Bitmap.createScaledBitmap(mask_over, screenwidth, screenwidth, false);
back_img=createBitmap_ScriptIntrinsicBlur(Bitmap.createScaledBitmap(cropview.croppedImage, screenwidth, screenwidth, false),25.0f);
LinearLayout.LayoutParams layoutParams111 = new LinearLayout.LayoutParams(screenwidth, screenwidth);
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