Per Google's Material Design guideline for Navigation drawer, to achieve Standard drawer for tablet or desktop devices, I would use NavigationView with SlidingPaneLayout for tablet devices instead of DrawerLayout for phone devices, which is to achieve Modal drawer.
I put a NavigationView as the first child view of SlidingPaneLayout. A problem occurred.
As you know SlidingPaneLayout's child views overlap if their combined width exceeds the available width in the SlidingPaneLayout. In this case, the child views expand to fill the available width in the SlidingPaneLayout. The user can slide the topmost view out of the way by dragging it back from the edge of the screen.
But my NavigationView's pane wouldn't slide. It just appears or disappears at maximum width without sliding animation.
How can I solve this?
<androidx.slidingpanelayout.widget.SlidingPaneLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- The first child view becomes the left pane. When the combined
desired width (expressed using android:layout_width) would
not fit on-screen at once, the right pane is permitted to
overlap the left. -->
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_view_header"
app:menu="@menu/navigation_view" />
<!-- The second child becomes the right (content) pane. In this
example, android:layout_weight is used to expand this detail pane
to consume leftover available space when the
the entire window is wide enough to fit both the left and right pane.-->
<fragment
android:id="@+id/navigationHost"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="320dp"
android:layout_weight="1"
android:layout_height="match_parent"
app:navGraph="@navigation/main" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
Add app:elevation="0dp"
to the NavigationView.
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:elevation="0dp"
app:headerLayout="@layout/navigation_view_header"
app:menu="@menu/navigation_view" />
If you inspect the layout, you can notice the NavigationView has elevation of 16dp
by default. This causes the problem. It is probably that SlidingPaneLayout handles the two child views under the condition that they have the same elevations (0dp
).
So a solution is to override NavigationView's default elevation (16dp
) with 0dp
.
Another solution is to wrap NavigationView with a FrameLayout or some ViewGroup.
<FrameLayout
android:layout_width="280dp"
android:layout_height="match_parent">
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_view_header"
app:menu="@menu/navigation_view" />
</FrameLayout>
Then, you should specify layout_width
with FrameLayout and NavigationView's layout_width
to match_parent
.
In spite of NavigationView's default elevation of 16dp
, for its parent ViewGroup's elevation is 0dp
, SlidingPaneLayout can properly handle.