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.
Related
I was working on the landscape layout for my activity. In landscape activity I happen to have the layout with xml code below.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="wrap_content"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="200dp"
android:background="#android:color/holo_blue_bright"
android:layout_height="match_parent"/>
<android.support.v4.widget.DrawerLayout
android:layout_width="200dp"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:background="#android:color/darker_gray"
android:layout_height="match_parent"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_gravity="end"
android:background="#android:color/holo_red_light"
android:layout_height="match_parent"/>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
The Problem arising here is that the drawer is not opening by edge swipe. BTW using LTR layout so end is right. By java invocation for opening drawer, the Drawer opens and touch events are also handled. Also all drawers are Unlocked as well. But still Drawer doesn't opens by swipe from right edge when Drawer layout is child of linear layout with horizontal orientation. if the first Frame:ayout in the linearLayout is of zero width then the drawer works.
Whats wrong with the Drawer Layout? How Can I fix this?
From the Android reference:
DrawerLayout acts as a top-level container for window content
The DrawerLayout needs to be the root element of the view. It can't be nested in the LinearLayout
I am making a Layout where I need to position a Toolbar below a Map Fragment. Well it may hear easy but from my small knowledge I hit upon a tricky problem.
Well I hv achieved how to get the toolbar below the fragment body but I hit on some problems:
When using Linear Layout, I split both the components using weights which was perfect as i needed it but couldnt get the Toolbar to the bottom of the Fragment.
While using Relative Layout, I was able to bring the toolbar below the fragment but since the map is big, i couldnt adjust the height of the map and the toolbar goes out of bounds.
What i need is the combined effect of weights from the LinearLayout and the 'android:Layout_below' effect from the Relative Layout.
I will post my code here:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/app_bar"
layout="#layout/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/map1"
/>
<fragment
android:id="#+id/map1"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
/>
</RelativeLayout>
My toolbar is in a separate Layout 'app_bar'
The Toolbar is just like any View, and can be placed wherever you want. This is a big difference between it, and the ActionBar.
Just place the element wherever you would like inside your layout.
In your case, don't place the Toolbar relative to the fragment, but relative to the parent (RelativeLayout) then you can control it's placement/size independent of your fragment (which you can then place relative to your Toolbar if you want that control)
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/app_bar"
layout="#layout/app_bar"
android:layout_width="match_parent"
android:layout_height="80dp"// or whatever...
android:layout_alignParentBottom="true"
/>
<fragment
android:id="#+id/map1"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_alignParentTop="true"
android:layout_above="#+id/app_bar"
android:layout_height="fill_parent"
/>
I have a NavigationView set up so that every time my hamburger icon is pressed a menu slides in from the left. The problem I'm facing is that the menu covers the entire width of the screen, rather than any value I give it in the XML. Everything is darkened when it's open. It is a transparent black background (I guess by default).
<android.support.v4.widget.DrawerLayout
android:id="#+id/nav_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:name="com.google.android.gms.maps.SupportMapFragment"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/list"
android:entries="#array/menuitems"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="left">
</ListView>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/drawer"/>
</android.support.v4.widget.DrawerLayout>
How can I make my NavigationView only take up a certain width of the screen rather then the entirety of it? Appreciate any advice.
EDIT:
Screenshot of the drawer when it's open (as you can see the whole width of the screen is darkened by the drawer's background)
First things first, Your drawer layout should have two child views. one that hosts the main content, one that will be the nav drawer. In this case your list view is coming up as the navigation drawer.
Also, you are mistaken about the navigation drawer(in this case the ListView) taking up the entire space. its taking only 240 dp. The rest of the main view will be in shadow(default behavior). You can see that its taking only 240 dp if you see where the separator lines between list view items end. The transparent background seems to have confused you.
This is a follow up question to this question:
Margin does not impact in "include"
I am trying to add a margin to an include layout. I have added layout_width and layout_height to the include element, but the margin is still ignored. Furthermore, when I try to auto complete the word "margin" in the layout xml file, this attribute is not even recognized.
So how can I add a margin to an include tag?
The layout:
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="#layout/main_status"
/>
<!--
As the main content view, the view below consumes the entire
space available using match_parent in both dimensions.
-->
<LinearLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
<!--
android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
If you're not building against API 17 or higher, use
android:layout_gravity="left" instead.
-->
<!--
The drawer is given a fixed width in dp and extends the full height of
the container.
-->
<fragment
android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="left"
tools:layout="#layout/fragment_navigation_drawer" />
As you can see, the LinearLayout's height is set to match_parent. I still want it like that, but that's what caused the included layout and container layout be on top of each other when trying to add margin inside the layout that I wanted to include.
So what I did that got me the effect I wanted was setting the paddingTop attribute of the linear layout container. It created some space between the included layout and the linear layout.
By default, eg. having Toolbar and some other Views in FrameLayout container causes Toolbar to appear on top of other views, no matter what their (views) order is.
Is it possible to force some of the views (eg. floating action buttons) to appear in front of Toolbar or should look for workaround?
edit:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/toolbar"/>
<!-- some RecyclerView goes here also -->
<com.github.clans.fab.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right"
android:src="#drawable/ic_content_add"
fab:fab_colorNormal="#color/accentColor"
fab:fab_colorPressed="#color/accentColor"
android:layout_marginRight="20dp"
/>
</FrameLayout>
Result:
Problem: The oval button appears in front of RecyclerView, but behind Toolbar.
The floating action button has to have equal or higher elevation as the toolbar. Assuming your toolbar has elevation set to 8dp, the FAB needs to have the same at least.
Basically widgets with higher elevation move physically above and stop respecting the XML order.