MrEngineer13 / SnackBar

toast-like alert pattern for Android inspired by the Google Material Design Spec

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

DrawerLayout behind SnackBar?

jonamireh opened this issue · comments

I'm using a layout with a DrawerLayout and when the drawer becomes active, it renders behind a SnackBar I have set in the current layout with an infinite duration. Although you can dismiss the SnackBar, is there anyway I can have the SnackBar render behind the DrawerLayout/make the DrawerLayout render above it?

Using the following code, I am able to achieve your desired behavior.

EDIT: This layout has issues relating to the SnackBar view container remaining on screen constantly when a SnackBar object is not used or the view hierarchy is recreated and the layout being altered after the SnackBar has been shown. See my comment below for an updated version.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            android:id="@id/snackContainer"
            layout="@layout/sb__snack"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"/>

        <FrameLayout
            android:id="@+id/root_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@id/snackContainer"
            android:layout_alignParentTop="true"/>

    </RelativeLayout>


    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@color/color_primary"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />


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

The SnackBar(Context, View) constructor appears to have a bug, so using an include tag, I was able to work around this by directly including the layout used for the SnackBar in my layout, which allows the DrawerLayout to draw the drawer overtop of the SnackBar. I then created a SnackBar using the included layout as the passed view:

new SnackBar(getActivity(), getActivity().findViewById(R.id.snackContainer));

Including it in the layout also has the added benefit of pushing the content view up so the SnackBar does not cover child views or parts of child views at the bottom of the content view.

Thank you! I just tried this out and it worked perfectly.

Going to go ahead and mark the issue as closed since the underlying bug has already been identified.

Glad I could help!

I just discovered two potential issues with the layout I provided.

First, it appears that the layout used by the SnackBar has an inherent height associated with it (before the SnackBar object manipulates it), and if a SnackBar object is not used on the include layout or the view hierarchy is recreated when a SnackBar object is no longer being used on it (i.e. a fragment that used a SnackBar object is replaced with one that does not and the screen is rotated), the area that would normally be taken up by the SnackBar view remains as an empty box permanently at the bottom of the screen until a SnackBar object is once again instantiated with the view, at which point the box disappears. Include tags don't have a visibility attribute, so it can't be set to GONE by default. Since you have an indefinite SnackBar, it probably will not affect you, but since I use it for transient messages, I've had to change my layout a bit to use a ViewStub that's inflated when the SnackBar is instantiated.

Second, using a RelativeLayout in the way I did results in a changed layout after the SnackBar has been shown. In my case, a centered view loses that property and is forced to the top of its container. I've found that using a LinearLayout with a child with 0dp height and nonzero weight in order to fill all space not taken up by the SnackBar view results in a much more consistent layout.

Here's the updated layout and constructor invocation.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

        <FrameLayout
            android:id="@+id/root_container"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"/>

        <ViewStub
            android:id="@id/snackContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout="@layout/sb__snack"/>

    </LinearLayout>


    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@color/color_primary"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />


</android.support.v4.widget.DrawerLayout>
getActivity().findViewById(R.id.snackContainer).setVisibility(View.VISIBLE); ////If view at R.id.snackContainer is a ViewStub, this inflates its layout, otherwise does nothing
new SnackBar(getActivity(), getActivity().findViewById(R.id.snackContainer)); //Find inflated view that replaced ViewStub