BottomNavigationView - Shadow and Ripple Effect

↘锁芯ラ 提交于 2019-11-28 20:45:29

Here is what I've achieved:

Ripple effect + Elevation gif

I've created a demo on GitHub to help you.

First of all use latest support library compile "com.android.support:design:$SUPPORT_VERSION"

It only works if you set white background color android:background="@android:color/white"

Note that ripple effect will disappear if you use app:itemBackground property or in your case it's design:itemBackground="...", so just remove it.

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:background="@android:color/white"
    app:elevation="16dp"
    app:itemIconTint="@drawable/nav_item_color_state"
    app:itemTextColor="@drawable/nav_item_color_state"
    app:menu="@menu/bottom_navigation_main" />

Handling enabled/disabled state:

You need to create selector file:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:color="@color/colorPrimary" />
    <item android:color="@android:color/darker_gray"  />
</selector>

If you want to change standard grey ripple effect change colorControlHighlight proproperty in AppTheme so it looks like following:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="colorControlHighlight">@color/colorPrimaryRipple</item>
</style>

Use 26% alpha for colored ripples.

<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryRipple">#423F51B5</color>
  1. For Shadow use elevation in your BottomNavigationView app:elevation="8dp".
  2. And for Ripples Effect you just need to remove app:itemBackground and set android:background to white color like that android:background="@android:color/white"

Full example below:

<android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_alignParentBottom="true"
        android:background="@android:color/white"
        android:clickable="true"
        app:elevation="8dp"
        app:itemIconTint="@drawable/nav_item_color_state"
        app:itemTextColor="@drawable/nav_item_color_state"
        app:menu="@menu/my_navigation_items" />

This is an issue in the Design library and has been reported here.

The shadow part of this question has already been resolved, so you should update your Gradle dependencies to 25.0.1 for the Support and Design library.

The Google engineers insists that the ripple effect issue has also been fixed, but I haven't been able to get this to work properly.

An example on how the XML for the BottomNavigationView could look like can be seen here:

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottom_navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:background="@android:color/black"
    app:itemBackground="@android:color/white"
    app:itemIconTint="@drawable/bottom_navigation_selector"
    app:itemTextColor="@drawable/bottom_navigation_selector"
    app:menu="@menu/bottom_navigation_menu" />

Star the issue to add awareness to it.

Nikola Despotoski

Take this FrameLayout that draws shadow and this gradient drawable xml:

public class DrawShadowFrameLayout extends FrameLayout {
    private Drawable mShadowDrawable;
    private final int mShadowElevation = 8;
    private int mWidth;
    private int mHeight;
    private boolean mShadowVisible = true;

    public DrawShadowFrameLayout(Context context) {
        this(context, null, 0);
    }

    public DrawShadowFrameLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DrawShadowFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mShadowDrawable = ContextCompat.getDrawable(getContext(), R.drawable.shadow);
        if (mShadowDrawable != null) {
            mShadowDrawable.setCallback(this);
        }
        setWillNotDraw(!mShadowVisible);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        updateShadowBounds();
    }


    private void updateShadowBounds() {
        if (mShadowDrawable != null) {
            mShadowDrawable.setBounds(0, 0, mWidth, mShadowElevation);
        }
        ViewCompat.postInvalidateOnAnimation(this);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (mShadowDrawable != null && mShadowVisible) {
            getBackground().setBounds(0, mShadowDrawable.getBounds().bottom, mWidth, mHeight);
            mShadowDrawable.draw(canvas);
        }
    }

    public void setShadowVisible(boolean shadowVisible) {
        setWillNotDraw(!mShadowVisible);
        updateShadowBounds();
    }

    int getShadowElevation() {
        return mShadowVisible ? mShadowElevation : 0;
    }

}

Wrap your BottomNavigationView inside this this layout like:

<DrawShadowFrameLayout>
  <BottomNavigationView />
</DrawShadowFrameLayout>

Unfortunately, the native shadow is drawn under the view, we have to mimic this upward shadow ourselves.

Dont forget to add android:elevation="8dp" for the DrawShadowFrameLayout too.

Another approach is extending BottomNavigationView and overriding draw() to do the same. This will help you loose one FrameLayout in your view hierarchy.

You might want to add a selector to your button like:

android:background="@drawable/my_selector"

/res/drawable/my_selector.xml:

<ripple android:color="@color/my_favourite_color"
    xmlns:android="http://schemas.android.com/apk/res/android" />

Read more: RippleDrawable

I've found a solution for ripple effect problem.

1) Since the android:background and app:itemBackground don't work correctly delete both of them from BottomNavigationView.

2) Create a new FrameLayout and put your BottomNavigationView inside FrameLayout.

3) change these properties of the FrameLayout:

android:layout_width="match_parent"
android:layout_height="wrap_content"

4)Finally Add your desired color for ButtomNavigationView into FrameLayout as android:background.

Example:

<FrameLayout
 android:id="@+id/buttomnavigation_container"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@color/blue"><!--Background color for BNV-->
 <android.support.design.widget.BottomNavigationView
    android:id="@+id/nav_view"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    app:itemIconTint="@color/bottom_navigation_colors"
    app:itemTextColor="@color/bottom_navigation_colors"
    app:labelVisibilityMode="labeled"
    app:menu="@menu/bottom_nav_menu"/>
</FrameLayout>

bottom_navigation_colors.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item
        android:state_checked="true"
        android:color="#FFFFFF" />
   <item
       android:state_checked="false"
       android:color="#C7FFFFFF" />
</selector>

What you can do is just wrap your BottomNavigationView in AppBarLayout for the same effect.

Like this

<com.google.android.material.appbar.AppBarLayout
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_width="match_parent"
            android:background="@android:color/white"
            android:layout_height="wrap_content">

        <com.google.android.material.bottomnavigation.BottomNavigationView
                android:id="@+id/bottomNav"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

</com.google.android.material.appbar.AppBarLayout>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!