Nouvel Travay
Nouvel Travay

Reputation: 6462

How to add a shadow above a view in android

I have a view that is to server as a footer title. It is just a view, that you may think of as a button or a textview or a layout (I am open to anything really). Here is the xml

<RelativeLayout>
   <ScrollView >… </ScrollView> //match parent width and height
   <MyBottomView/> // align parent bottom
 </RelativeLayout>

So as you can see the ScrollView does scroll below MyBottomView. I want to add a top shadow to the MyBottomView so it looks more like Material Design. How might I do that?

Upvotes: 18

Views: 47293

Answers (5)

Ivo Stoyanov
Ivo Stoyanov

Reputation: 18699

If you need to have shadow just on one side of the view (e.g. on top), you can add another View before it and use gradient shadow for its background.

Here is the gradient file top_shadow_gradient.xml that you have to store in drawable folder:

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

And here is a sample layout how to use it:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:orientation="vertical">

    <View
        android:layout_width="match_parent"
        android:layout_height="8dp"
        android:background="@drawable/top_shadow_gradient" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:orientation="vertical"
        android:paddingTop="8dp">
        
        <!-- Put your content here-->
   
    </LinearLayout>

</LinearLayout>

Important: The root layout have to be transparent (android:background="@android:color/transparent") and your "content" layout need to have white background (android:background="#ffffff").

And this is the result: enter image description here

Upvotes: 84

yerty
yerty

Reputation: 343

I have updated Ivo's excellent answer by including the use of ConstraintLayouts.

Drawable: shadow_top.xml

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

Layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <androidx.constraintlayout.widget.ConstraintLayout
      android:id="@+id/cl_topView"
      android:layout_width="match_parent"
      android:layout_height="0dp"
      app:layout_constraintBottom_toTopOf="@id/cl_bottomView"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent">
      
         ... nested views

    </androidx.constraintlayout.widget.ConstraintLayout>

    <View
      android:id="@+id/v_shadowTop"
      android:layout_width="match_parent"
      android:layout_height="3dp"
      android:background="@drawable/shadow_top"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintBottom_toTopOf="@id/cl_bottomView"/>

   <androidx.constraintlayout.widget.ConstraintLayout
      android:id="@+id/cl_bottomView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@id/cl_topView">

         ... nested views

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Result: Following the steps above I was able to get the top shadow indicated by the arrow in the picture below.

enter image description here

For those newer to Android Development:

Height Adjustment: The height of the shadow is controlled by the view's, "v_shadowTop", height (currently 3dp).

Gradient Adjustment: The gradient's color is controlled by the last six characters (hex code) of the startColor (currently 000000) and endColor (currently ffffff) in the "shadow_top.xml" drawable.

The transparency is controlled by the first two characters of the startColor (currently 40) and endColor (currently 10) in the shadow_top.xml drawable.

Upvotes: 5

piotrek1543
piotrek1543

Reputation: 19351

Here are some solutions for this problem - choose your best:

There is no such attribute in Android, to show a shadow. But possible ways to do it are:

  1. Add a plain LinearLayout with grey color, over which add your actual layout, with margin at the bottom and right equal to 1 or 2 dp.
  1. Have a 9-patch image with a shadow and set it as the background to your Linear layout.

and

There is also another solution to the problem by implementing a layer-list that will act as the background for the LinearLayoout.

Add background_with_shadow.xml file to res/drawable. Containing:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item >
        <shape 
            android:shape="rectangle">
        <solid android:color="@android:color/darker_gray" />
        <corners android:radius="5dp"/>
        </shape>
    </item>
    <item android:right="1dp" android:left="1dp" android:bottom="2dp">
        <shape 
            android:shape="rectangle">
        <solid android:color="@android:color/white"/>
        <corners android:radius="5dp"/>
        </shape>
    </item>
</layer-list>

Then add the layer-list as background in your LinearLayout.

<LinearLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="@drawable/background_with_shadow"/>

You can also read: http://odedhb.blogspot.com/2013/05/android-layout-shadow-without-9-patch.html

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:padding="10dp"
    android:background="#CC55CC">
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TableLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:stretchColumns="0">
            <TableRow>
                <LinearLayout
                    android:id="@+id/content"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content">
                    <TextView  
                        android:layout_width="fill_parent" 
                        android:layout_height="wrap_content"
                        android:background="#FFFFFF" 
                        android:text="@string/hello" />
                </LinearLayout>
                <View
                    android:layout_width="5dp"
                    android:layout_height="fill_parent"
                    android:layout_marginTop="5dp"
                    android:background="#55000000"/>
            </TableRow>
        </TableLayout>
        <View
            android:layout_width="fill_parent"
            android:layout_height="5dp"
            android:layout_marginLeft="5dp"
            android:background="#55000000"/>
    </LinearLayout>
</FrameLayout>
  • You can also use specific drawable form Android resources to mimic a shadow effect. Look at: Android View shadow or just read a post below:

I'm using Android Studio 0.8.6 and I couldn't find:

android:background="@drawable/abc_menu_dropdown_panel_holo_light"

so I found this instead:

android:background="@android:drawable/dialog_holo_light_frame"

and it looks like this:

picture of a smartphone running Android, with the code example running


If you're interested in clean Material Design effect, read some documentation like below:

Upvotes: 10

Mahmoud Ayman
Mahmoud Ayman

Reputation: 1324

Top only Shadow:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

<item>
    <shape>
        <padding
            android:top="@dimen/_2sdp" />
        <solid android:color="@color/red" />
        <corners android:radius="@dimen/_8sdp" />
    </shape>
</item>

<!-- Background -->
<item>
    <shape>
        <solid android:color="@color/white" />
        <corners android:radius="@dimen/_8sdp" />
    </shape>
</item>

if you want shadow to appear in other areas add padding bottom, right, left

Result:

1

Upvotes: 3

AA_PV
AA_PV

Reputation: 1359

On hack I found for this is to wrap your view in a parent and use rotate. E.g. if you have a cardview and are adding elevation to it, you can put two rotates like this to achieve a shadow above instead of below:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipToPadding="false"
    android:paddingBottom="10dp"
    android:rotation="180">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:rotation="180"
        app:cardElevation="8dp">
    <!--Card view content-->
    </android.support.v7.widget.CardView>
</RelativeLayout>

This gives something like the attached screenshot.

enter image description here

There's still a problem with this - this requires the paddingBottom to be set on the parent layout which means it'll be obvious that any scrollable sibling above the layout isn't going below it.

So even in today's age of elevation and outline provider, it's better to add a translucent view instead. :(

Upvotes: 5

Related Questions