简体   繁体   English

将小吃店移至底部栏上方

[英]Move snackbar above the bottom bar

I am facing some problems with new bottom bar.我在使用新底栏时遇到了一些问题。
I can't force to move the snackbar above the bottom bar (this is how design guideline told me should be https://www.google.com/design/spec/components/bottom-navigation.html#bottom-navigation-specs ).我不能强制将小吃栏移到底部栏上方(这是设计指南告诉我的方式应该是https://www.google.com/design/spec/components/bottom-navigation.html#bottom-navigation-specs )。

This is my activity_main.xml这是我的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>

This is my app_bar_main_activity.xml这是我的 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>

The snackbar in main_activity.java looks like this main_activity.java 中的小吃店看起来像这样

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

错误...零食栏应该在底部栏上方

With the material components library you can use the setAnchorView method to make a Snackbar appear above a specific view.使用材质组件库,您可以使用setAnchorView方法使Snackbar出现在特定视图上方。

In your case if you are using a BottomAppBar and a fab, you should define the fab in the setAanchorView .在您的情况下,如果您使用BottomAppBar和 fab,则应在setAanchorView定义fab Something like:类似的东西:

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

The result:结果:

在此处输入图片说明

With a BottomNavigationView you can define it as anchorView:使用BottomNavigationView您可以将其定义为anchorView:

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

Result:结果:

在此处输入图片说明

You can do this programmatically without cluttering your xml with extra CoordinatorLayouts by changing the snackbar's margins.您可以通过更改小吃店的边距以编程方式执行此操作,而不会用额外的 CoordinatorLayouts 使您的 xml 混乱。

Java example: 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 single line: 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()

Assuming your are working with CoordinatorLayout you can modify the Snackbar's layoutparams before calling show().假设您正在使用 CoordinatorLayout,您可以在调用 show() 之前修改 Snackbar 的 layoutparams。 By setting the anchorId and anchorGravity the snackBar will display above the bottom nav bar:通过设置 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

replace your xml ->替换你的 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>

and The Snackbar code will be和 Snackbar 代码将是

Snackbar.make(findViewById(R.id.placeSnackBar), "Replace with your own action", Snackbar.LENGTH_LONG)
            .setAction("Action", null).show();

There is great article about how to use it HERE .有一个关于如何使用它的优秀文章这里 There you will know how to make snackbar above BottomNavigationBar在那里你会知道如何在底部导航栏上方BottomNavigationBar

Basically the code below presents most common usage of Toolbar together with BottomNavigationBar and FrameLayout as Fragment container基本上,下面的代码展示了Toolbar最常见的用法以及作为 Fragment 容器的BottomNavigationBarFrameLayout

Important!重要! Notice that请注意

  1. fab button uses anchor to be placed correcty and useCompactPadding to preserve margins fab 按钮使用锚点正确放置并使用CompactPadding来保留边距
  2. BottomNavigationView uses layout_behaviour to handle scrolling and SnackBar position 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" />

Implmenetation of Behaviour don't hesitate to use that !行为的实现不要犹豫使用它! It's easy and friendly ;) (scrolling)它既简单又友好;)(滚动)

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

There is a simple way, with the new Material Design:有一个简单的方法,使用新的材料设计:

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

So the Snackbar will show above the BottomNavigationView .因此Snackbar将显示在BottomNavigationView

It can be done simply if the parent layout was Coordinator layout.如果父布局是协调器布局,则可以简单地完成。

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

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

I am using the BottomNavigationView and Snackbar from the design support library version 25.3.1 on target OS kitkat, lollipop and Marshmallow.我在目标操作系统 kitkat、棒棒糖和棉花糖上使用了设计支持库版本 25.3.1 中的 BottomNavigationView 和 Snackbar。 On lollipop and above Snackbar is hiding behind BottomNavigationView but in Kitkat BottomNavigationView is hidden behind Snackbar.在棒棒糖和上面 Snackbar 隐藏在 BottomNavigationView 后面,但在 Kitkat BottomNavigationView 隐藏在 Snackbar 后面。

I tried to show the Snackbar with a different approach.我试图用不同的方法展示 Snackbar。 When the Snackbar is shown the BottomNavigationView is translated on Y-axis(scrolled down) using the translationY property and Interpolator .当显示 Snackbar 时,BottomNavigationView 使用translationY 属性和 Interpolator在 Y 轴上平移(向下滚动)。 Once Snackbar is gone, the BottomNavigationView appears again with the same translationY property.一旦 Snackbar 消失,BottomNavigationView 会再次出现,并具有相同的 translationY 属性。

Hiding the BottomNavigationView (towards bottom):隐藏底部导航视图(朝底部):

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

Showing the BottomNavigationView back on screen:在屏幕上显示 BottomNavigationView:

bottomNavigationView.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
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);

Instead of programmatically manipulating CoordinatorLayout parameters, I found that you can place a GuideLine (or a View, if you are not using ConstraintLayout) above which the Snackbar may be placed.我发现您可以放置​​一个 GuideLine(或一个视图,如果您不使用 ConstraintLayout),而不是以编程方式操作 CoordinatorLayout 参数,Snackbar 可以放置在其上方。 I'm using 1 here to indicate 100% meaning the bottom of the parent ConstraintLayout:我在这里使用 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" />

Use Viewbinding + this code to place the snackbar above the Guide:使用 Viewbinding + 此代码将小吃栏放置在指南上方:

Snackbar
        .make(containerView, alert.description, Snackbar.LENGTH_LONG).apply {
            anchorView = binding?.snackbarAnchor
            show()
        }

For any of you that cannot use the CoordinatorLayout , even with the Anchor solution such as it seems in my case对于无法使用CoordinatorLayout任何人,即使使用Anchor解决方案,例如在我的情况下

It might be helpful to know you can add a listener to the Snackbar and at most (if not all) views can add layout_marginBottom at Runtime.知道您可以向Snackbar添加侦听器并且最多(如果不是全部)视图可以在运行时添加layout_marginBottom可能会有所帮助。

From my initial testing, it seems to be working quite well.从我最初的测试来看,它似乎工作得很好。

following is my code, hopes it will help anyone以下是我的代码,希望它能帮助任何人

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

    }

Inspired by Gabriele Mariotti's answer here is my Kotlin solution:受 Gabriele Mariotti 回答的启发,我的 Kotlin 解决方案是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM