45

First off, I know that this question has been asked before, but it hasn't been answered before. I hope someone can give me an answer.

In my application, I use the Toolbar from Appcompat_v7 (API 21). This is my code:

<android.support.v7.widget.Toolbar
    style="@style/DarkActionbarStyle"
    android:id="@+id/toolBar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/actionbar_height" />

And this is the ToolBar style I use:

<style name="DarkActionbarStyle" parent="@style/Widget.AppCompat.Toolbar">
    <item name="android:background">?attr/colorPrimary</item>
    <item name="titleTextAppearance">@style/ActionBarTitle</item>
    <item name="android:elevation">2dp</item>
    <item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
    <item name="theme">@style/ThemeActionBarDark</item>
</style>

<style name="ThemeActionBarDark" parent="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="actionBarItemBackground">@drawable/btn_dark_orange</item>
    <item name="selectableItemBackground">@drawable/btn_dark_orange</item>
</style>

The problem is, that elevation doesn't work pre-lollipop. So my question is: Is it possible to have a shadow under the ToolBar on pre-lollipop devices?

9 Answers9

74

This worked for me very well:

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/primary"
    card_view:cardElevation="4dp"
    card_view:cardCornerRadius="0dp">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/primary"
        android:minHeight="?attr/actionBarSize" />

</android.support.v7.widget.CardView>
Islam A. Hassan
  • 1,357
  • 15
  • 20
  • This is working for me with API 22, but not with API 21 (my `minSdk` is 19). I'm using the same code as you. Anyway, my application main theme inherits from `Theme.AppCompat.Light.NoActionBar`. I don't know whether this may be the cause of the bug. Any idea? (I just started android development). – link Apr 23 '15 at 11:52
  • 2
    Fixed it. For those having problems with toolbar margins in pre lollipop releases, please refer to this accepted answer: http://stackoverflow.com/questions/27477371/android-elevation-not-showing-a-shadow/27518160#comment51895526_27518160 – Eduardo Lino Aug 13 '15 at 19:16
  • Solution doesn't work. See http://imgur.com/dQa6NJj . I think we must override the AppBarLayout to add the shadow to it – Trancer Feb 11 '17 at 10:47
18

Using CardView container for toolbar is a bad idea.

CardView is heavy, especially for low end devices.

The best way is to put a gradient Shadow view below the toolbar. Shadow view must be a direct child to the coordinator layout. ie. The appbar which contains toolbar and shadow View must be siblings.

Add this view component to your layout.

 <View
    android:id="@+id/gradientShadow"
    android:layout_width="match_parent"
    android:layout_height="5dp"
    android:background="@drawable/toolbar_shadow"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_collapseMode="pin"/>

The drawable toolbar_shadow.xml

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

This will solve the problems in pre-lollipop devices. But we don't want this shadow in lollipop and above devices so make visibility to gone in devices with lollipop and above.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        findViewById(R.id.gradientShadow).setVisibility(View.GONE);
}

Done.

shijin
  • 2,998
  • 1
  • 24
  • 30
  • You can disable elevation in appbar layout in xml to use your gradient all the version. `android:stateListAnimator="@null"` – Akexorcist May 28 '18 at 09:22
12

You can add the shadow (elevation) back by using a FrameLayout with foreground="?android:windowContentOverlay". The elevation attribute is not supported pre-Lollipop. So if you are using FrameLayout like fragment container just add foreground attribute to it.

Anggrayudi H
  • 14,977
  • 11
  • 54
  • 87
Stoycho Andreev
  • 6,163
  • 1
  • 25
  • 27
  • I finally went with this way after testing some of the other answers here. This only works with a frameLayout though, but there are some ways to extend a Relativelayout and use a foreground: https://gist.github.com/shakalaca/6199283 – Tristan Vanderaerden Mar 09 '15 at 21:14
  • if you have case witch you don't use fragments and FrameLayout then you should make ImageView right under (below) your toolbar and give it shadow drawable like background attribute. For example use @Alessandro Roaro answer and create shadow drawable from this [link](http://stackoverflow.com/questions/27474766/how-to-show-the-shadow-of-the-actionbartoolbar-of-the-support-library-on-all-an) – Stoycho Andreev Mar 10 '15 at 09:36
  • Using "?android:windowContentOverlay" everywhere seemed to be more consistent though. I don't like to mix up two approaches. I have Fragments almost everywhere in my layouts, so it's no real problem. – Tristan Vanderaerden Mar 10 '15 at 14:25
  • It seems like a solution for this issue. But the shadow does not look very well and realistic. See the picture with Pre-Lollipop and Marshmallow: http://imgur.com/tyIWMUJ – Trancer Feb 11 '17 at 11:01
7

As I've had issues with the CardView widget method, I've used the FrameLayout method as mentioned by @Sniper; it is working perfectly!

I just wanted to share the code snippet you'll have to use. Just put this directly under the toolbar where your main content starts:

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:foreground="?android:windowContentOverlay">

And don't forget to close with:

</FrameLayout>
MegaCookie
  • 5,017
  • 3
  • 21
  • 25
6

It's possible to have real shadows - animated and generated. The method used by Lollipop is available since Froyo. Hardware acceleration used for shadow generation is available since Honeycomb I guess. Here's how it works:

  • draw your view to an off-screen bitmap with LightingColorFilter set to 0,0
  • blur the black shape (the off-screen bitmap) using the ScriptIntrinsicBlur class and elevation value as radius
  • draw the bitmap beneath the view

It requires adding custom elevation attributes, custom views capable of rendering shadows, and using render script and the compatibility library (for older devices). I'm not going to dive into the details, because there's a lot of them including issues with compilation and minor performance optimisations. But it's possible.

Why there's no shadows in the official support library?

  • it would require changes in the UI framework as it's impossible to freely draw outside view bounds
  • smooth animation requires a quite good GPU

See:

Zielony
  • 16,239
  • 6
  • 34
  • 39
5

I'm using this answer:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/orange"
    android:titleTextAppearance="@color/White"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

    <View
        android:layout_width="match_parent"
        android:layout_height="5dp"
        android:background="@drawable/toolbar_shadow" />
</LinearLayout>

toolbar_shadow.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="#3f3f3f"
        android:endColor="@android:color/transparent"
        android:angle="270" />
</shape>
Community
  • 1
  • 1
Leebeedev
  • 2,126
  • 22
  • 31
4

You can't use the elevation attribute before API 21 (Android Lollipop). You can however add the shadow programmatically, for example using a custom view placed below the Toolbar.

For example:

<ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        android:background="@drawable/shadow"/>

Where the shadow is a drawable with a black gradient.

Alessandro Roaro
  • 4,665
  • 6
  • 29
  • 48
2

To show shadow under your toolbar please use AppBarLayout available in Google Android Design Support Library. Here is an example of how it should be used.

<android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
   <android.support.v7.widget.Toolbar
            android:layout_height="?attr/actionBarSize"
            android:layout_width="match_parent"/>
     </android.support.design.widget.AppBarLayout>

To use Google Android Design Support Library enter following into your build.gradle file:

 compile 'com.android.support:design:22.2.0'
Michal
  • 6,453
  • 2
  • 24
  • 23
  • 15
    How was this answer upvoted? OP asked for pre-lollipop elevation and this answer doesn't elevate the AppBarLayout on pre-lollipop devices. This only adds an elevation effect on v5.0+ devices. – Yani2000 Jun 02 '16 at 10:51
1

The solution with a view to add a shadow manually would work as long as there are no action bar menus. If so, the shadow view would stop before the action bar icons.

i think it is easier to have a vertical linear layout with appbar on the top and a view for shadow below it as the next linear layout item or in my case, it is

<LinearLayout Vertical> 
  <v7 toolbar/>
  <RelativeLayout>
     <View for shadow with alignParent_top= true/>
      ....
  </RelativeLayout>
</LinearLayout>

I really hope the near future appCompat would fix this.

onusopus
  • 1,234
  • 11
  • 16