64

我在使用新的底栏时遇到了一些问题。
我不能强制将小吃栏移到底栏上方(这是设计指南告诉我的应该是https://www.google.com/design/spec/components/bottom-navigation.html#bottom-navigation-specs)。

这是我的 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">

<include
    layout="@layout/app_bar_main_activity"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:headerLayout="@layout/nav_header_main_activity"
    app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>

这是我的 app_bar_main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="test.tab_activity">

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="@dimen/appbar_padding_top"
    android:theme="@style/MyAppTheme.NoActionBar.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/main_activity_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/MyAppTheme.NoActionBar.PopupOverlay">

    </android.support.v7.widget.Toolbar>

</android.support.design.widget.AppBarLayout>



<android.support.v4.view.ViewPager
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

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

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_add_white_24dp" />

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        style="@style/AppTabLayout"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="?attr/colorPrimary"
        />

</LinearLayout>

main_activity.java 中的snackbar 看起来像这样

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(findViewById(R.id.main_content), "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

错误...小吃栏应该在底栏上方

4

13 回答 13

65

使用材料组件库,您可以使用该setAnchorView方法在Snackbar特定视图上方显示。

在您的情况下,如果您使用的是 a和fabBottomAppBar,则应在. 就像是:setAanchorView

FloatingActionButton fab = findViewById(R.id.fab);
Snackbar snackbar = Snackbar.make(view, "Snackbar over BottomAppBar", Snackbar.LENGTH_LONG);
snackbar.setAnchorView(fab);

结果:

在此处输入图像描述

使用 aBottomNavigationView您可以将其定义为 anchorView:

    Snackbar snackbar = Snackbar.make(view,"Snackbar over BottomNav",Snackbar.LENGTH_INDEFINITE);
    snackbar.setAnchorView(bottomNavigationView);
    snackbar.show();

结果:

在此处输入图像描述

于 2019-11-01T20:52:47.277 回答
47

您可以通过更改快餐栏的边距以编程方式执行此操作,而无需使用额外的 CoordinatorLayouts 使您的 xml 混乱。

Java 示例:

Snackbar snack = Snackbar.make(findViewById(R.id.coordinatorLayout), 
    "Your message", Snackbar.LENGTH_LONG);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) 
    snack.getView().getLayoutParams();
params.setMargins(leftMargin, topMargin, rightMargin, bottomBar.height);
snack.getView().setLayoutParams(params);
snack.show();

Kotlin 单行:

Snackbar.make(coordinatorLayout, "Your message", Snackbar.LENGTH_LONG).apply {view.layoutParams = (view.layoutParams as CoordinatorLayout.LayoutParams).apply {setMargins(leftMargin, topMargin, rightMargin, bottomBar.height)}}.show()
于 2016-08-25T21:04:29.773 回答
44

假设您正在使用 CoordinatorLayout,您可以在调用 show() 之前修改 Snackbar 的 layoutparams。通过设置 anchorId 和 anchorGravity,snackBar 将显示在底部导航栏上方:

val layoutParams = snackbar.view.layoutParams as CoordinatorLayout.LayoutParams
layoutParams.anchorId = R.id.navigation //Id for your bottomNavBar or TabLayout
layoutParams.anchorGravity = Gravity.TOP
layoutParams.gravity = Gravity.TOP
snackbar.view.layoutParams = layoutParams
于 2018-01-27T02:45:41.937 回答
34

替换你的 xml ->

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="test.tab_activity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/main_activity_toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways">

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>



    <android.support.v4.view.ViewPager
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:id="@+id/placeSnackBar">

            <android.support.v4.view.ViewPager
                android:id="@+id/view_pager"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1" />

            <android.support.design.widget.FloatingActionButton
                android:id="@+id/fab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end|bottom"
                android:layout_margin="@dimen/fab_margin"
                android:src="@drawable/ic_menu_gallery" />

        </android.support.design.widget.CoordinatorLayout>

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:background="?attr/colorPrimary" />

    </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

和 Snackbar 代码将是

Snackbar.make(findViewById(R.id.placeSnackBar), "Replace with your own action", Snackbar.LENGTH_LONG)
            .setAction("Action", null).show();
于 2016-03-31T12:07:42.400 回答
16

这里有一篇关于如何使用它的好文章。在那里你会知道如何在上面制作小吃店BottomNavigationBar

Toolbar基本上,下面的代码展示了与片段容器一起使用BottomNavigationBarFrameLayout作为片段容器的最常见用法

重要的!请注意

  1. fab 按钮使用锚点正确放置并使用CompactPadding保留边距
  2. BottomNavigationView使用layout_behaviour处理滚动和 SnackBar 位置

    <android.support.design.widget.AppBarLayout
        android:id="@+id/myAppBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:descendantFocusability="beforeDescendants"
        android:focusableInTouchMode="true"
        android:theme="@style/AppTheme.AppBarOverlay">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:contentInsetStart="0dp"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/AppTheme.PopupOverlay"/>
    </android.support.design.widget.AppBarLayout>
    
    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        />
    
    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        app:menu="@menu/bottom_navigation"
        app:layout_behavior="murt.shoppinglistapp.ui.BottomNavigationBehavior"
        android:background="?android:attr/windowBackground"
        />
    
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab_add_shopping_list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:useCompatPadding="true"
        app:srcCompat="@drawable/ic_add_24"
        app:layout_anchor="@id/navigation_bar"
        app:layout_anchorGravity="top|right"
        android:layout_gravity="top"
        />
    

行为的实施不要犹豫使用它!这既简单又友好;)(滚动)

class BottomNavigationBehavior : CoordinatorLayout.Behavior<BottomNavigationView> {

    constructor(): super()

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    override fun layoutDependsOn(parent: CoordinatorLayout, child: BottomNavigationView,
                                 dependency: View): Boolean {
        if (dependency is Snackbar.SnackbarLayout) {
            updateSnackbar(child, dependency)
        }
        return super.layoutDependsOn(parent, child, dependency)
    }

    private fun updateSnackbar(child: View, snackbarLayout: Snackbar.SnackbarLayout) {
        if (snackbarLayout.layoutParams is CoordinatorLayout.LayoutParams) {
            val params = snackbarLayout.layoutParams as CoordinatorLayout.LayoutParams

            params.anchorId = child.id
            params.anchorGravity = Gravity.TOP
            params.gravity = Gravity.TOP
            snackbarLayout.layoutParams = params
        }
    }

    override fun onStartNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: BottomNavigationView,
        directTargetChild: View,
        target: View,
        nestedScrollAxes: Int
    ): Boolean {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
    }

    override fun onNestedPreScroll(
        coordinatorLayout: CoordinatorLayout,
        child: BottomNavigationView,
        target: View,
        dx: Int,
        dy: Int,
        consumed: IntArray
    ) {
        if (dy < 0) {
            showBottomNavigationView(child)
        } else if (dy > 0) {
            hideBottomNavigationView(child)
        }
    }

    private fun hideBottomNavigationView(view: BottomNavigationView) {
        view.animate().translationY(view.height.toFloat())
    }

    private fun showBottomNavigationView(view: BottomNavigationView) {
        view.animate().translationY(0f)
    }
}
于 2018-03-21T00:59:31.990 回答
15

使用新的 Material Design 有一个简单的方法:

Snackbar snackbar= Snackbar.make(view, text, duration);
snackbar.setAnchorView(bottomBar);

所以Snackbar将显示在BottomNavigationView.

于 2019-09-09T19:31:56.893 回答
4

如果父布局是协调器布局,则可以简单地完成。

CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams)
                snackbar.getView().getLayoutParams();
        params.setAnchorId(R.id.navigation); //id of the bottom navigation view
        params.gravity = Gravity.TOP;
        params.anchorGravity = Gravity.TOP;
        snackbar.getView().setLayoutParams(params);
于 2019-05-17T08:28:07.460 回答
3

我发现您可以放置​​一个 GuideLine(或一个视图,如果您不使用 ConstraintLayout),而不是以编程方式操作 CoordinatorLayout 参数,而 Snackbar 可以放置在其上方。我在这里使用 1 表示 100% 表示父 ConstraintLayout 的底部:

<androidx.constraintlayout.widget.Guideline
android:id="@+id/snackbar_anchor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="1" />

使用 Viewbinding + 此代码将快餐栏放置在指南上方:

Snackbar
        .make(containerView, alert.description, Snackbar.LENGTH_LONG).apply {
            anchorView = binding?.snackbarAnchor
            show()
        }
于 2021-04-19T09:49:54.050 回答
3

要实现这一点,您必须注意您提供给snackbar 的ViewGroup 是CoordinatorLayout,否则snackbar 不会显示在底部导航菜单上方。

于 2018-08-05T13:14:34.717 回答
2

我在目标 OS kitkat、lollipop 和 Marshmallow 上使用设计支持库版本 25.3.1 中的 BottomNavigationView 和 Snackbar。在棒棒糖和上面的 Snackbar 上隐藏在 BottomNavigationView 后面,但在 Kitkat 中,BottomNavigationView 隐藏在 Snackbar 后面。

我试图用不同的方法展示 Snackbar。当 Snackbar 显示时,使用translateY 属性和 Interpolator在 Y 轴上平移 BottomNavigationView(向下滚动)。一旦 Snackbar 消失,BottomNavigationView 将再次出现,并带有相同的 translationY 属性。

隐藏 BottomNavigationView(朝向底部):

CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) bottomNavigationView.getLayoutParams();
bottomNavigationView.animate().translationY(bottomNavigationView.getHeight() + layoutParams.bottomMargin).setInterpolator(new LinearInterpolator()).start();

在屏幕上显示 BottomNavigationView:

bottomNavigationView.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
于 2017-08-08T11:40:53.227 回答
2
Snackbar outerSnackBar = Snackbar.make(findViewById(android.R.id.content), "Your text", Snackbar.LENGTH_INDEFINITE);
View view = outerSnackBar.getView();
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)view.getLayoutParams();
params.gravity = Gravity.BOTTOM;
params.setMargins(0, 0, 0, 150);
view.setLayoutParams(params);
于 2020-01-17T13:25:32.330 回答
0

对于任何不能使用的人CoordinatorLayout,即使使用Anchor我这样的解决方案

知道您可以向运行时Snackbar添加的最多(如果不是全部)视图添加侦听器可能会有所帮助layout_marginBottom

从我最初的测试来看,它似乎工作得很好。

以下是我的代码,希望对任何人都有帮助

public class ItemActivity extends AppCompatActivity {

    private ConstraintLayout mBottomViewConstraintLayout;
    private int mPrevBottomPadding = 0;
    private Snackbar mSnackbar;
    private Snackbar.Callback mCallback = new Snackbar.Callback() {
        @Override
        public void onShown(Snackbar sb) {
            super.onShown( sb );
            addMarginToBottomView();
        }

        @Override
        public void onDismissed(Snackbar transientBottomBar, int event) {
            super.onDismissed( transientBottomBar, event );
            initMarginToBottomView();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        //.....

        mSnackbar = Snackbar.make(
                findViewById( android.R.id.content ),
                getString( R.string.snackbar_message_undo_item_removed ),
                Snackbar.LENGTH_LONG)
                .setAction( getString( R.string.snackbar_action_undo ),
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                mItemDao.undoDelete(  );
                            }
                        } )
                .addCallback( mCallback )
                .setDuration( Constants.SNACKBAR_DURATION_MS );
    }

    private void addMarginToBottomView() {
        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) mBottomViewConstraintLayout.getLayoutParams();

        mPrevBottomPadding = layoutParams.bottomMargin;

        layoutParams.bottomMargin += mSnackbar.getView().getHeight();

        mBottomViewConstraintLayout.setLayoutParams(layoutParams);
    }

    private void initMarginToBottomView() {
        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) mBottomViewConstraintLayout.getLayoutParams();

        layoutParams.bottomMargin = mPrevBottomPadding;

        mBottomViewConstraintLayout.setLayoutParams(layoutParams);
    }

    private void showSnackbar() {

        mSnackbar.show();

    }
于 2020-03-26T08:35:26.147 回答
0

受 Gabriele Mariotti 的回答启发,这里是我的 Kotlin 解决方案:

Snackbar.make(show_snack_btn, "Yeeeaaay!", Snackbar.LENGTH_LONG).also {
    it.anchorView = fab
}.show()
于 2021-03-26T12:57:37.320 回答