How to Set Shadow Effect on Imageview

Drop shadow for custom imageView

To achieve this you should use CardView. So it will be something like:

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#687199"
>

<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="40dp"
app:cardElevation="16dp"
>

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/test"
/>
</androidx.cardview.widget.CardView>

</FrameLayout>

Example

You just need to play around with app:cardElevation and app:cardCornerRadius to get the shadow you need.

Also, keep in mind that the Android shadow system draws darker and longer shadows when objects are closer to the bottom of the screen.

How to add shadow around circular imageview

Here, I share my best practice to show a shadow effect to a circular image/resource with some details.

Sample Image

The above example image's icon is 56dp x 56dp and is cropped with a zoomed view so it may not look attractive but the results will show good on an actual device under the naked eye.

The above example is delivered by using:

  • Some amount of elevation, to let shadow.
  • Provide margin to the view almost double of elevation to fit the shadow.
  • Ensure the parent view provides the space almost double of elevation to fit the shadow.
  • Create and use an OutlineProvider to create the shadow.

Now here we begin with the code.

<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/margin_14dp"> // Point no. 3

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/img"
android:layout_width="@dimen/margin_56dp"
android:layout_height="@dimen/margin_56dp"
android:layout_margin="@dimen/margin_14dp" // Point no. 2
android:elevation="@dimen/margin_8dp" // Point no. 1
android:src="@drawable/ic_bell" />
</FrameLayout>

Let's proceed to point no. 4, here is the OutlineProvider class for a Circular Outline.

import android.graphics.Outline;
import android.view.View;
import android.view.ViewOutlineProvider;

public class CircularOutlineProvider extends ViewOutlineProvider {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), (view.getWidth() / 2F));
}
}

We left to use the OutlineProvider in our Java/Kotlin class to do the magic at runtime.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
findViewById(R.id.img).setOutlineProvider(new CircularOutlineProvider());

End of Magic Session!

For more experience and enhance details, please read the official article.

Custom ImageView with drop shadow

Okay, I don't foresee any more answers on this one, so what I ended up going with for now is just a solution for rectangular images. I've used the following NinePatch:


alt text

along with the appropriate padding in XML:

<ImageView
android:id="@+id/image_test"
android:background="@drawable/drop_shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="6px"
android:paddingTop="4px"
android:paddingRight="8px"
android:paddingBottom="9px"
android:src="@drawable/pic1"
/>

to get a fairly good result:


alt text

Not ideal, but it'll do.

How to set shadow effect on ImageView

Sadly there is no straight-forward way to get this working for android. But there are some options that you can try.

Option #1

There are several unsupported drawing operations for hardware accelerated layers, that includes SetShadowLayer for non-text views.

So, in order to get the SetShadowLayer render for a non-text view, you need to set the LayerType rendering as SOFTWARE as explained in this solution.

SetLayerType(LayerType.Software, null);

But the major drawback of course is that it can be a performance issue.

Option #2

Second option is to use an radial gradient to emulate the shadow. I had implemented it as a renderer (but you should be able to implement it as an effect too). The result of course is not as great as a blurred shadow effect. You will also have to set the right Padding to let some space for the shadow to render, and be visible under the image.

protected override void DispatchDraw(global::Android.Graphics.Canvas canvas)
{
try
{
var nativeCtrl = Control;
var formsElement = Element;
if (nativeCtrl == null || formsElement == null)
{
base.DispatchDraw(canvas);
return;
}

//convert from logical to native metrics if need be
var shadowDistanceX = 10f;
var shadowDistanceY = 10f;
var shadowRadius = 5f;
var shadowOpacity = .5f;
var shadowColor = Color.Black;
var cornerRadius = 0.2f;

var bounds = formsElement.Bounds;

var left = shadowDistanceX;
var top = shadowDistanceY;
var right = Width + shadowDistanceX;
var bottom = Height + shadowDistanceY;

var rect = new Android.Graphics.RectF(left, top, right, bottom);

canvas.Save();
using (var paint = new Android.Graphics.Paint { AntiAlias = true })
{
paint.SetStyle(Android.Graphics.Paint.Style.Fill);

var nativeShadowColor = shadowColor.MultiplyAlpha(shadowOpacity * 0.75f).ToAndroid();
paint.Color = nativeShadowColor;

var gradient = new Android.Graphics.RadialGradient(
0.5f, 0.5f,
shadowRadius,
shadowColor.ToAndroid(),
nativeShadowColor,
Android.Graphics.Shader.TileMode.Clamp
);
paint.SetShader(gradient);

//convert from logical to native metrics if need be
var nativeRadius = cornerRadius;
canvas.DrawRoundRect(rect, nativeRadius, nativeRadius, paint);

var clipPath = new Android.Graphics.Path();
clipPath.AddRoundRect(new Android.Graphics.RectF(0f, 0f, Width, Height), nativeRadius, nativeRadius, Android.Graphics.Path.Direction.Cw);
canvas.ClipPath(clipPath);
}
canvas.Restore();
}
catch (Exception ex)
{
//log exception
}

base.DispatchDraw(canvas);
}
Option #3

Another option would be to use SkiaSharp for Forms - i.e. create a container (or layered) view that renders the shadow around the child view (image). You can either have SkiaSharp render the image too, or embed a XF based image control inside the layout.

protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
{
var imgInfo = args.Info;
var surface = args.Surface;
var canvas = surface.Canvas;

var drawBounds = imgInfo.Rect;
var path = new SKPath();
var cornerRadius = 5f;

if (cornerRadius > 0)
{
path.AddRoundedRect(drawBounds, cornerRadius, cornerRadius);
}
else
{
path.AddRect(drawBounds);
}

using (var paint = new SKPaint()
{
ImageFilter = SKImageFilter.CreateDropShadow(
offsetX,
offsetY,
blurX,
blurY,
color,
SKDropShadowImageFilterShadowMode.DrawShadowOnly),
})
{
canvas.DrawPath(path, paint);
}
}

How can we set shadow effect for View in Android?

You can create your own "shadow view"

<View
android:id="@+id/shadow_view"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_gravity="bottom"
android:background="@drawable/shadow_gradient" />

and add the shadow drawable to it:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:endColor="@android:color/transparent"
android:startColor="#8f000000" />
</shape>

The height is up to you, to experiment and see what works best for you as is the angle and start colour of the drawable. You just need to align this view layout to any view layout you want to have a shadow and you are good.



Related Topics



Leave a reply



Submit