Move snackbar above the bottom bar

杀马特。学长 韩版系。学妹 提交于 2019-11-27 12:03:07

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

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

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

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

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

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

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.

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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!