Appcompat v21 Toolbar elevation pre-lollipop
Solution 1
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>
Solution 2
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.
Solution 3
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.
Solution 4
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>
Solution 5
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:
Related videos on Youtube
Tristan Vanderaerden
Updated on March 27, 2020Comments
-
Tristan Vanderaerden about 4 years
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?
-
Tristan Vanderaerden over 9 yearsThis seems to be the only way to add a shadow under the toolbar. But I was secretly hoping for there to be another solution :p
-
Alessandro Roaro over 9 yearsAlso the CardView implementation in the support api uses a shadow created programmatically to reproduce the shadow
-
Tristan Vanderaerden about 9 yearsI 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: gist.github.com/shakalaca/6199283
-
Stoycho Andreev about 9 yearsif 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
-
Tristan Vanderaerden about 9 yearsUsing "?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.
-
link about 9 yearsThis 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 fromTheme.AppCompat.Light.NoActionBar
. I don't know whether this may be the cause of the bug. Any idea? (I just started android development). -
Eduardo Lino over 8 yearsFixed it. For those having problems with toolbar margins in pre lollipop releases, please refer to this accepted answer: stackoverflow.com/questions/27477371/…
-
Yani2000 almost 8 yearsHow 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.
-
Trancer about 7 yearsSolution doesn't work. See imgur.com/dQa6NJj . I think we must override the AppBarLayout to add the shadow to it
-
Trancer about 7 yearsIt 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: imgur.com/tyIWMUJ
-
Akexorcist almost 6 yearsYou can disable elevation in appbar layout in xml to use your gradient all the version.
android:stateListAnimator="@null"