底部导航视图 - 阴影和涟漪效果

24
一周前,BottomNavigationView 发布时我非常高兴,但我遇到了一些问题,导致我无法解决它,比如想在 BottomNavigationView 上看到一个阴影,与 Google Photos Android 应用程序显示的方式相同:

The shadow over Bottom Navigation Bar

如果我们点击 Google Photos 菜单项,可以看到一个水波纹效果,其颜色像图标和文本颜色(选中时)一样为蓝色。

实现 Google 提供的解决方案后,只会显示灰色的涟漪效果颜色,更糟糕的是,当我们更改 bottomnavigationview 的背景颜色 (design:itemBackground="...") 时,不会显示效果。

有人知道怎么解决吗?


1
只需将BottomNavigationView的itemBackground属性设置为白色,就像下面这样: app:itemBackground="@color/colorWhite" - Subhan Ali
10个回答

58

这是我所取得的进展:

涟漪效果+高度动画演示

我在 GitHub 上创建了一个演示,以帮助你。

首先使用最新的支持库 compile "com.android.support:design:$SUPPORT_VERSION"

只有当你设置白色背景颜色 android:background="@android:color/white"时才有效。

请注意,如果您使用 app:itemBackground 属性或在您的情况下为 design:itemBackground="...",涟漪效果将消失,因此请移除它。

<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" />

处理启用/禁用状态:

您需要创建选择器文件:

<?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>

如果你想要改变标准的灰色涟漪效果,请在App主题中更改colorControlHighlight属性,使其看起来像下面这样:

<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>

使用26%的透明度来呈现有颜色的涟漪效果。

<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryRipple">#423F51B5</color>

4
确实,只有当背景为白色时,阴影才会出现。这很愚蠢。你有什么想法为什么会这样? - WindRider
我同意这很令人沮丧,但不知道为什么。 - luksha
嗨@luksha,我完全按照你说的做了,但还是没有起作用:(令人惊讶的是,如果我将BottomNavigationBar放在屏幕顶部,它会提高导航视图的底部边框。然而,当我将它放在屏幕底部时,高度不再起作用。 - inverted_index
你是我的救星!谢谢。我一直搞不清楚那个阴影去哪里了,也不知道为什么。 - Oksana Kryvenko

23
  1. 对于底部导航栏,请使用app:elevation="8dp"来设置阴影。
  2. 对于涟漪效果,您只需要删除app:itemBackground并将android:background设置为白色,如下所示:android:background="@android:color/white"

以下是完整示例:

<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" />

6
在最新的Material design库中,更改BottomNavigationView项目点击时的涟漪颜色非常容易。只需在BottomNavigationView中添加 app:itemRippleColor="@color/your_color" 即可。下面是完整代码示例:

在build.gradle中添加依赖项

build.gradle

implementation "com.google.android.material:material:$materialDesignVersion"

activity_main.xml

<com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/_5sdp"
        android:background="@drawable/bottom_navigation_background"
        app:itemRippleColor="@color/red"
        app:labelVisibilityMode="labeled"
        app:itemIconTint="@color/bottom_navigation_menu_item_tint"
        app:itemTextColor="@color/bottom_navigation_menu_item_tint"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:menu="@menu/home_bottom_navigation_menu" />

它对您有用吗? - Nininea

3

这是设计库中的问题,并已在此处报告。

该问题的影子部分已经得到解决,因此您应该将Gradle依赖项更新为25.0.1,以使用Support和Design库。

Google工程师坚称水波纹效果问题也已经解决,但我还没有成功地实现它。

BottomNavigationView的XML示例可以在此处查看:

<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这个问题以增加其知名度。


3
只需将此属性添加到:app:itemRippleColor="@color/orange"
<FrameLayout
    android:id="@+id/frameLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:layout_gravity="bottom"
        android:id="@+id/bottomNavigation"
        android:background="@color/dark"
        app:itemRippleColor="@color/orange"
        android:layout_width="match_parent"
        app:menu="@menu/bottom_nav_menu"
        app:itemIconTint="@color/bottom_nav_color"
        app:itemTextColor="@color/bottom_nav_color"
        android:layout_height="wrap_content"/>

</FrameLayout>

请添加一些链接以展示代码是否可行。 - Sharath

1

您可能需要为按钮添加选择器,例如:

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" />

阅读更多:RippleDrawable


1

使用这个FrameLayout,可以绘制阴影和这个渐变的 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;
    }

}

将您的BottomNavigationView包装在此布局中,如下所示:

<DrawShadowFrameLayout>
  <BottomNavigationView />
</DrawShadowFrameLayout>

很不幸,本地阴影是在视图下面绘制的,我们必须自己模仿这个向上的阴影。

别忘了为 DrawShadowFrameLayout 添加 android:elevation="8dp"

另一种方法是扩展 BottomNavigationView 并重写 draw() 来完成相同的工作。这将帮助您减少视图层次结构中的一个 FrameLayout

enter image description here Zoomed


1
我找到了一个解决水波纹效果问题的方法。
1)由于android:background和app:itemBackground无法正常工作,请从BottomNavigationView中删除它们两个。
2)创建一个新的FrameLayout,并将BottomNavigationView放在FrameLayout中。
3)更改FrameLayout的这些属性:
android:layout_width="match_parent"
android:layout_height="wrap_content"

4)最后将所需的颜色添加到FrameLayout中作为ButtomNavigationView的android:background

示例:

<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>

Image


0

你可以将BottomNavigationView包裹在AppBarLayout中,以达到相同的效果。

像这样

<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>

-1
如何将水波纹效果添加到BottomNavigationView?
  1. 如果您没有为BottomNavigationView属性 app:itemBackground 设置自定义可绘制对象,则只需添加以下内容即可添加涟漪效果。

    android:background="@android:color/white"
    
  2. 如果您已经使用了自定义的可选择器

    app:itemBackground="@drawable/tab_selector"
    

然后将涟漪标签添加到自定义可绘制对象中。

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

        </item>

这个解决方案不会产生水波纹效果,而是在单击菜单项时将整个“正方形”的颜色设置为@color/red。 - Gianluca Veschi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接