Move snackbar above the bottom bar

AndroidLayoutAndroid SnackbarSnackbar

Android Problem Overview


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

This is my 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

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

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

Wrong...snackbar should be above bottom bar

Android Solutions


Solution 1 - Android

With the material components library you can use the setAnchorView method to make a Snackbar appear above a specific view.

In your case if you are using a BottomAppBar and a fab, you should define the fab in the setAanchorView. Something like:

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

The result:

enter image description here

With a BottomNavigationView you can define it as anchorView:

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

Result:

enter image description here

Solution 2 - Android

You can do this programmatically without cluttering your xml with extra CoordinatorLayouts by changing the snackbar's margins.

Java example:

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:

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

Solution 3 - Android

Assuming your are working with CoordinatorLayout you can modify the Snackbar's layoutparams before calling show(). By setting the anchorId and anchorGravity the snackBar will display above the bottom nav bar:

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

Solution 4 - Android

replace your 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.make(findViewById(R.id.placeSnackBar), "Replace with your own action", Snackbar.LENGTH_LONG)
            .setAction("Action", null).show();

Solution 5 - Android

There is great article about how to use it HERE. There you will know how to make snackbar above BottomNavigationBar

Basically the code below presents most common usage of Toolbar together with BottomNavigationBar and FrameLayout as Fragment container

Important! Notice that

  1. fab button uses anchor to be placed correcty and useCompactPadding to preserve margins

  2. BottomNavigationView uses layout_behaviour to handle scrolling and SnackBar position

    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/container" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="murt.shoppinglistapp.ui.main.MainActivity">

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

Solution 6 - Android

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.

Solution 7 - Android

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

Solution 8 - Android

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. I'm using 1 here to indicate 100% meaning the bottom of the parent 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:

Snackbar
        .make(containerView, alert.description, Snackbar.LENGTH_LONG).
        .setAnchorView(binding?.snackbarAnchor)
        .show()

Solution 9 - Android

To achieve this you must take care that the ViewGroup you are providing to the snackbar is a CoordinatorLayout else the snackbar would not be shown above the bottom navigation menu.

Solution 10 - Android

I am using the BottomNavigationView and Snackbar from the design support library version 25.3.1 on target OS kitkat, lollipop and Marshmallow. On lollipop and above Snackbar is hiding behind BottomNavigationView but in Kitkat BottomNavigationView is hidden behind Snackbar.

I tried to show the Snackbar with a different approach. When the Snackbar is shown the BottomNavigationView is translated on Y-axis(scrolled down) using the translationY property and Interpolator. Once Snackbar is gone, the BottomNavigationView appears again with the same translationY property.

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

Solution 11 - Android

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

Solution 12 - Android

Inspired by Gabriele Mariotti's answer here is my Kotlin solution:

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

Solution 13 - Android

For any of you that cannot use the CoordinatorLayout, even with the Anchor solution such as it seems in my case

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.

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

    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWladislawView Question on Stackoverflow
Solution 1 - AndroidGabriele MariottiView Answer on Stackoverflow
Solution 2 - AndroidJim PekarekView Answer on Stackoverflow
Solution 3 - AndroidjesusF10View Answer on Stackoverflow
Solution 4 - AndroidZahidul IslamView Answer on Stackoverflow
Solution 5 - AndroidmurtView Answer on Stackoverflow
Solution 6 - AndroidAnsshkkiView Answer on Stackoverflow
Solution 7 - AndroidJarin RocksView Answer on Stackoverflow
Solution 8 - AndroidNino van HooffView Answer on Stackoverflow
Solution 9 - Androidsanjay kumarView Answer on Stackoverflow
Solution 10 - AndroidPrashantView Answer on Stackoverflow
Solution 11 - Androidujwall patelView Answer on Stackoverflow
Solution 12 - AndroidMeLeanView Answer on Stackoverflow
Solution 13 - AndroidepicView Answer on Stackoverflow