Android 将snackbar移动到底部栏上方

Android 将snackbar移动到底部栏上方,android,layout,android-snackbar,snackbar,Android,Layout,Android Snackbar,Snackbar,我在使用新的底部栏时遇到了一些问题。 我不能强迫把蛇形杆移到底部杆的上方(这是设计指南告诉我的) 这是我的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.androi

我在使用新的底部栏时遇到了一些问题。
我不能强迫把蛇形杆移到底部杆的上方(这是设计指南告诉我的)

这是我的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>

替换您的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的边距,您可以通过编程方式实现这一点,而不会使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();
科特林单线:

Snackbar.make(coordinatorLayout, "Your message", Snackbar.LENGTH_LONG).apply {view.layoutParams = (view.layoutParams as CoordinatorLayout.LayoutParams).apply {setMargins(leftMargin, topMargin, rightMargin, bottomBar.height)}}.show()

我在目标操作系统kitkat、棒棒糖和棉花糖上使用25.3.1版设计支持库中的BottomNavigationView和Snackbar。在棒棒糖上和上面,Snackbar隐藏在BottomNavigationView后面,但在Kitkat中,BottomNavigationView隐藏在Snackbar后面

我试着用不同的方法展示Snackbar。当显示Snackbar时,BottomNavigationView将使用translationY属性和插值器在Y轴上平移(向下滚动)。Snackbar消失后,BottomNavigationView将再次显示,并具有相同的translationY属性

隐藏底部导航视图(朝向底部):

CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) bottomNavigationView.getLayoutParams();
bottomNavigationView.animate().translationY(bottomNavigationView.getHeight() + layoutParams.bottomMargin).setInterpolator(new LinearInterpolator()).start();
bottomNavigationView.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
在屏幕上显示底部导航视图:

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

假设您正在使用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

有一篇关于如何使用它的好文章。在那里,您将知道如何在
BottomNavigationBar

基本上,下面的代码展示了
工具栏
以及
底部导航栏
框架布局
作为片段容器的最常见用法

重要!请注意

  • fab按钮使用锚定正确放置,并使用压缩填充保留边距
  • BottomNavigationView
    使用布局行为处理滚动和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{
    构造函数():super()
    构造函数(context:context,attrs:AttributeSet):super(context,attrs)
    覆盖有趣的layoutDependsOn(父项:CoordinatorLayout,子项:BottomNavigationView,
    依赖项:视图):布尔值{
    if(依赖项为Snackbar.Snackbar布局){
    updateSnackbar(子项,依赖项)
    }
    返回super.layoutDependsOn(父、子、依赖项)
    }
    私有乐趣更新nackbar(子:视图,snackbarLayout:Snackbar.snackbarLayout){
    if(snackbarLayout.layoutParams是CoordinatorLayout.layoutParams){
    val params=snackbarLayout.layoutParams作为CoordinatorLayout.layoutParams
    params.anchorId=child.id
    params.anchorgavity=重力.TOP
    params.gravity=gravity.TOP
    snackbarLayout.layoutParams=参数
    }
    }
    覆盖启动时的乐趣嵌套滚动(
    协调布局:协调布局,
    子项:BottomNavigationView,
    directTargetChild:视图,
    目标:视图,
    嵌套滚动轴:Int
    ):布尔值{
    返回NestedScrollAxis==ViewCompat.SCROLL\u AXIS\u VERTICAL
    }
    覆盖所有已存储的数据滚动(
    协调布局:协调布局,
    子项:BottomNavigationView,
    目标:视图,
    dx:Int,
    狄:Int,
    消耗:无阵列
    ) {
    if(dy<0){
    showBottomNavigationView(子级)
    }如果(dy>0),则为else{
    hideBottomNavigationView(儿童)
    }
    }
    private fun hideBottomNavigationView(视图:底部导航视图){
    view.animate().translationY(view.height.toFloat())
    }
    私人娱乐节目BottomNavigationView(视图:BottomNavigationView){
    view.animate().translationY(0f)
    }
    }
    
    要实现这一点,您必须注意提供给snackbar的视图组是一个协调布局,否则snackbar将不会显示在底部导航菜单上方。

    如果父布局是协调布局,则可以简单地完成此操作

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

    采用新材料设计有一种简单的方法:

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

    因此,
    Snackbar
    将显示在
    BottomNavigationView

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

    如果您使用的是
    BottomAppBar
    和fab,则应在
    setAanchorView
    中定义fab。 比如:

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

    使用
    BottomNavigationView
    可以将其定义为anchorView:

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


    对于不能使用
    协调器布局的任何人,即使使用
    锚定解决方案,如

    知道您可以将侦听器添加到
    Snackbar
    ,并且最多(如果不是所有)视图可以在运行时添加
    布局\u 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();
    
        }
    

    受Gabriele Mariotti的启发,以下是我的Kotlin解决方案:

    Snackbar.make(show_snack_btn, "Yeeeaaay!", Snackbar.LENGTH_LONG).also {
        it.anchorView = fab
    }.show()
    

    我发现可以将一条准则(或视图,如果不使用ConstraintLayout的话)放置在Snackbar的上方,而不是通过编程方式操纵CoordinatorLayout参数。我在这里使用1表示100%,表示父约束列表的底部:

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

    共享您的完整布局文件。您的布局文件不完整。已编辑我的问题。我想,这是不必要的。你想把snackbar放在bottombar上面吗?是的,就像谷歌的设计指南一样。注意:如果你在片段中显示snackbar,请确保你没有使用com.android。支持:desi
    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();
    
        }
    
    Snackbar.make(show_snack_btn, "Yeeeaaay!", Snackbar.LENGTH_LONG).also {
        it.anchorView = fab
    }.show()
    
    <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" />
    
    Snackbar
            .make(containerView, alert.description, Snackbar.LENGTH_LONG).apply {
                anchorView = binding?.snackbarAnchor
                show()
            }