Android Bottom Navigation Bar with drop shadow - android

I'm implementing Bottom Navigation Bar in Android app using Google's support design library v25.1.0. Is there any way to add drop shadow effect, same as current Android native Google Photos app?

You can draw your own shadow just above the bottom bar using simple View and its background:
<View
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_above="#id/bottom_bar"
android:background="#drawable/shadow"/>
drawable/shadow.xml:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#1F000000"
android:endColor="#android:color/transparent"
android:angle="90" />
</shape>
Also, there are no compatibility issues if use this approach.

You can use elevation to add shadows to any view
<TextView
android:id="#+id/myview"
...
android:elevation="2dp"
android:background="#drawable/myrect" />
Refer this for more information

For those using a CoordinatorLayout with the Bottom Navigation Bar (or BottomAppBar), you can use the following to attach a shadow above the bar:
<View
android:layout_width="match_parent"
android:layout_height="4dp"
android:background="#drawable/shadow"
app:layout_anchor="#+id/toolbar"
app:layout_anchorGravity="top"/>
Obviously, replace the #+id/toolbar with the id of the Bottom Navigation Bar

For those using Material Component - this has been fixed by com.google.android.material:material:1.1.0-alpha09.
Available since 1.1.0-alpha05 : https://github.com/material-components/material-components-android/releases/tag/1.1.0-alpha05
Use android:elevation="4dp" to set elevation shadow.
Also, do not forget to set clipChildren="false" on your main layout, otherwise, the shadow will be overwritten.

Related

BottomNavigationView inside a BottomAppBar with transparent background

I have been combining the new(ish) Material BottomAppBar with a standard BottomNavigationView. My xml is like this:
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottom_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
app:fabAlignmentMode="center">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="#android:color/transparent"
app:itemTextAppearanceActive="#style/AppTheme.Text.BottomNavText.Active"
app:itemTextAppearanceInactive="#style/AppTheme.Text.BottomNavText"
app:labelVisibilityMode="labeled"
app:menu="#menu/bottom_nav_menu" />
</com.google.android.material.bottomappbar.BottomAppBar>
On the previous version - 1.0.0 - this was working fine, and I could still see the FAB inset as expected. The only minor drawback is this version of the material components library hadn't sorted the elevation effect of the bottom app bar, and so the distinction between the bar and the content above wasn't clear.
When I upgrade to the latest library, which at the time of writing I believe is implementation 'com.google.android.material:material:1.1.0-alpha09', I get the BottomAppBar elevation effects, but when I apply the transparent background to the BottomNavigationView, I get a very strange visual effect that for the life of me I cannot understand.
If I remove the transparent background color, then the effect goes but I lose the FAB inset, as below:
If I remove the bottom navigation view child altogether, and just have the BottomAppBar, I see the visual effect as normal, but without my navigation:
I would love either:
- A good solution to incorporate bottom navigation view inside a BottomAppBar while retaining version 1.1.0 libraries nice elevation effect, and also have the BottomNavigationView effectively inside it so I retain all the benefits of that navigation component
- Or an explanation for what on earth is causing that peculiar first elevation effect, and ideally a way to fix it
Ok, this is nothing to do with BottomAppBar... the background problem happens on BottomNavigationView regardless of where it is, in material library 1.1.0- ....
This is (I think) a bug with the recent version of BottomNavigationView in which it sets a tintable MaterialShapeDrawableBackground as its background if background is either null or a ColorDrawable... and when you set a color in xml, it will be a ColorDrawable (including transparent). Here is the issue in the BottomNavigationView code:
if (getBackground() == null || getBackground() instanceof ColorDrawable) {
// Add a MaterialShapeDrawable as background that supports tinting in every API level.
ViewCompat.setBackground(this, createMaterialShapeDrawableBackground(context));
}
Which gets what must be the random shadow shape you see above.
Solution
The workaround is to set a background in the xml which is neither null or a ColorDrawable. I created my own drawable, which is just a transparent rectangle, and set that as the BottomNavigationView background, and it works.
background_transparent.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="10dp"
android:shape="rectangle" >
<solid android:color="#00000000" />
</shape>
And now the updated BottomNavigationView xml:
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
style="#style/BottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="#drawable/background_transparent"
app:itemTextAppearanceActive="#style/AppTheme.Text.BottomNavText.Active"
app:itemTextAppearanceInactive="#style/AppTheme.Text.BottomNavText"
app:labelVisibilityMode="labeled"
app:menu="#menu/bottom_nav_menu" />
And the result:

Shadow at the top of Bottom App Bar

I am using the new Bottom App Bar from the Material Design Components. I am trying to give shadow at the top of the Bottom App Bar like the one in Google Tasks app as shown below.
I have tried using both android:elevation and app:elevation attribute. Please help.
I ended up using this solution.
Step 1
Create a shape_drawable.xml file in the drawable folder as shown below:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#1F000000"
android:endColor="#android:color/transparent"
android:angle="90" />
</shape>
Step 2
Create a View, set the shape_drawable.xml as its background and then place the view just above the BottomAppBar.
<View
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_above="#id/bottom_bar"
android:background="#drawable/shape_drawable"/>
Elevation has been fixed in the Android material components 1.1.0 (alpha) release according to this commit.
Edit
for those wondering, this is how you add the new dependency:
dependencies {
// ...
implementation 'com.google.android.material:material:1.1.0-alpha02'
// ...
}
More information about getting started can be found here and info about releases can be found here.
Cheers!

How to change FAB background color

I am using Floating Action Button and I want to change the background color.
Here is my code
<android.support.design.widget.FloatingActionButton
android:id="#+id/btnfab"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_gravity="right|center_vertical"
android:layout_marginBottom="20dp"
android:src="#drawable/search" />
Here is the code I am using to try and achieve this:
1- android:background="#color/mycolor"
2- android:backgroundTint="#color/white"
I am also getting corners on my FAB as shown in image. How should I remove those corner shadows?
You can remove problematic shadow by adding this attributes to your FloatingActionButton:
app:borderWidth="0dp"
app:elevation="6dp"
There is no background color for FloatingActionButton. You change this component color by:
app:backgroundTint="#color/YOURCOLOR"
Remember to have in your parent layout following line:
xmlns:app="http://schemas.android.com/apk/res-auto"
Declare following in your app style:
<item name="colorAccent">#color/yourColor</ item>
cheers
First create a style in your styles.xml:
<style name="PrimaryActionButton" parent="Theme.AppCompat.Light">
<item name="colorAccent">#color/colorPrimary</item>
</style>
Then set the theme of your fab to this style:
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_favorite_white_24dp"
android:theme="#style/PrimaryActionButton"
app:fabSize="normal"
app:rippleColor="#color/colorAccent" />
You can see full descrption in:
Android: Floating Action button
Please update your android support and android material design libraries in build.gradle.
(Add please your build.gradle file above)
According to these sites:
[CodePath] Floating Action Buttons,
[Big Nerd Ranch] Floating Action Buttons in Android Lollipop
and Android Developers reference you should use only:
android:backgroundTint="#color/white"
As I remember, this shadow is well-know problem for Floating action buttons, so please take a look at these additional libraries:
http://android-arsenal.com/tag/173
which may help you to replace this broken element.
Check also:
Change color of Floating Action Button from Appcompat 22.2.0 programmatically
Change background on FloatingActionButton?
Hope it help.

CardView compatibility problems on Pre-Lollipop

I have some problems using the new CardView
That's my current situation: I want to use a CardView to provide a Floating Action Button for all devices (also Pre-Lollipop)
my activity's layout looks like this
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cardview="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#cdcdcd"
android:focusable="false">
<include layout="#layout/toolbar"/>
<android.support.v7.widget.CardView
android:layout_width="58dp"
android:layout_height="58dp"
cardview:cardPreventCornerOverlap="true"
android:layout_gravity="bottom|right"
android:layout_marginBottom="16dp"
android:layout_marginRight="18dp"
cardview:cardCornerRadius="29dp"
cardview:cardBackgroundColor="?attr/colorPrimary">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:layout_margin="12dp"
android:src="#android:drawable/ic_menu_edit"/>
</android.support.v7.widget.CardView>
Running the app on a Nexus 5 (4.4.4) the screen looks like this:
now I want to set the cardElevation by setting this in the xml
cardview:cardElevation="8dp"
After starting the app the button looks like this (it isn't a circle anymore):
It seems setting the card elevation also affects the view's dimensions... If you take now a closer look to picture #1 you can see, that this button isn't also a perfect circle.
Is there a way to figure that out? I also tried to set this
cardview:cardPreventCornerOverlap="false"
But it also has no affect
Thanks guys :)
Using CardView for FAB shadows is not the best idea. CardView is a layout, so it's pretty heavy. It's also very limited on pre-Lollipop versions. The shadow is not animated, corners pad the content and there's no ripple. Seems like there's no good method to achieve 100% FABs using only AppCompat.
In general I'm not happy being limited to AppCompat, so I wrote my own Button classes based on regular ones. I was able to achieve pretty good results as you can see on the screenshot. It's Gingerbread and there are animated shadows, ripples, vector graphics, etc. It's a pretty large repository, so I'm unable to give you a short solution here, but if you wish, check out the code on github.
You could try using the FAB from this MaterialDesign library if you're desperate for the shadow effect on older devices.
You can find the library at https://github.com/navasmdc/MaterialDesignLibrary
<com.gc.materialdesign.views.ButtonFloat
android:id="#+id/buttonFloat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="24dp"
android:background="#1E88E5"
materialdesign:animate="true"
materialdesign:iconDrawable="#drawable/ic_action_new" />
Alternatively you could create your own shadow resource in your drawables folder, and add the shape below your button, something like this:
<shape android:shape="oval"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#color/black_alpha"/>
<corners android:radius="20dip"/>
And create a layer list resource where you include your button and the shadow
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/shadow"/>
<item
android:drawable="#drawable/button"
android:bottom="4px" />
</layer-list>

Android Navigation Drawer and windowActionBarOverlay = true

I'm trying to implement the new Android Navigation Drawer in my application. I have created a BaseActivity.java that handles the Drawer setup and listeners, and I have two subactivities that extend this base class. On the second activity, I plan to use a different action bar style, using the following attrs:
<item name="android:windowActionBarOverlay">true</item>
<item name="android:background">#android:color/transparent</item>
to make the action bar transparent, and make content richer, as there is a picture header in my layout.
I've achieved just that, but now the problem is, that because the content is expanding to take advantage of the extra space of using the ActionBar as overlay, the Navigation Drawer itself is expanding too and it overlaps the ActionBar, creating a pretty awful looking layout:
What I'd like to have done, is the actual content (frame layout that will be populated with a fragment) to take up the extra space, but have the nav drawer still go underneath the action bar, similar to the Play Music App:
Any ideas on what I can do to make that happen?
EDIT So, as per Ahmad's assistance I set the marginTop on the ListView only. Here's the layout:
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
<!-- This was added after seeing the crazy effect, but does nothing -->
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_width="240dp"
android:layout_height="fill_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:background="?attr/listviewBackground"
/>
And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
Not sure what's causing it :(
And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
If you set your ListView gravity to start|bottom it solves your problem. No additional margin is added at the bottom. Looks like the DrawerLayout default gravity is start|center
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"/>
In case anyone is interested in another take to this question. Here's what happened.
I tried setting only the margin to the top of the list view like this:
android:layout_marginTop="?android:attr/actionBarSize"
But as mentioned on the edited question, that had a weird behaviour where there was also a margin on the bottom despite not being set on the layout resource file.
So, I was looking closely at the Play Music App and noticed that it's not actually a margin, but rather some padding, and additionally they are using a custom background that fills the space specified by the padding with a transparent color.
Here's what I did:
Set Padding at the top of the ListView, rather than margin:
android:paddingTop="?android:attr/actionBarSize"
As said before, it's important to not hard code the dimensions as they vary per device.
Create a custom drawable that has a top part transparent, and then rest of a solid color:
It looks somehow like this:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="#80000000" />
</shape>
</item>
<item android:top="#dimen/action_bar_default_height">
<shape
android:shape="rectangle">
<solid android:color="#color/light_gray" />
</shape>
</item>
Note that I tried to use ?android:attr/actionBarSize on the drawable, but that made the app force close. Instead, I searched through grepcode and found a few dimen files with different sizes for the action bar, so I added those to my own project's dimen files.
For values: 48dp
For values-land: 40dp
For values-sw600dp: 56dp
And after that, I think I looks great, notice on the screenshot how the listview and the actionbar don't overlap, and the transparent part of the listview is just the right size.
Hope that helps anyone who was wondering how to achieve this.
You can set a margin at the top of your layout, so that the content draws itself below the ActionBar.
Just add this in your parent layout:
android:layout_marginTop="?android:attr/actionBarSize"
The attribute actionBarSize refers to, like you would have already guessed, to the size of the ActionBar. You can't set an absolute value as a margin, since the ActionBar does not always have the same size across all Android devices (It's bigger on tablets, smaller on handset devices).
Edit:
Set the margin to the ListView.
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
The Google Music app does the same:
I solved this problem using paddingTop:
<FrameLayout
android:id="#+id/menu_frame"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:paddingTop="?attr/actionBarSize" >
<ListView
android:id="#+id/left_drawer_list"
android:layout_width="240dp"
android:layout_height="match_parent" />
</FrameLayout>
Hope that helps
I have created a working demo following the above guide and tested on 2.x to 5.x
You can clone from Github
The important thing to play around is in Main Activity
toolbar = (Toolbar) findViewById(R.id.toolbar);
res = this.getResources();
this.setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
ScrimInsetsFrameLayout scrimInsetsFrameLayout = (ScrimInsetsFrameLayout)
findViewById(R.id.linearLayout);
scrimInsetsFrameLayout.setOnInsetsCallback(this);
}
and the call back
#Override
public void onInsetsChanged(Rect insets) {
Toolbar toolbar = this.toolbar;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
toolbar.getLayoutParams();
lp.topMargin = insets.top;
int top = insets.top;
insets.top += toolbar.getHeight();
toolbar.setLayoutParams(lp);
insets.top = top; // revert
}
Absolutely the Theme for V21 does the magic
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- API 21 theme customizations can go here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/accent_material_light</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>

Categories

Resources