Implementing Navigation Drawer Without TitleBar - android

I'm planning to implement a navigation bar to let users navigate to different activites.
But here's the problem,
I've found plenty articles about creating a navigation drawer but it seems doesn't work for me , because my UI doesn't have any titlebar.
And what i actually want is to call up the navigation drawer whenever users press on a button near to the navigation drawer.
Is there any possible way to do this ?

It is very simple.
Here is your main activity's layout, activity_main.xml:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="match_parent">
<FrameLayout
android:animateLayoutChanges="true"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame" />
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/drawer_list_header"
app:menu="#menu/navigation"/>
</android.support.v4.widget.DrawerLayout>
And here's your MainActivity:
public class MainActivity extends AppCompatActivity {
NavigationView navigationView;
DrawerLayout drawerLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.navi_1:
// on 1st item in the menu, do something
break;
case R.id.navi_2:
// on 2nd item in the menu, do something
break;
}
drawerLayout.closeDrawers();
return false;
}
});
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
}
// [...]
private void openDrawer() {
if (!drawerLayout.isDrawerOpen(navigationView)) {
drawerLayout.openDrawer(navigationView);
}
}
private void closeDrawer() {
if (drawerLayout.isDrawerOpen(navigationView)) {
drawerLayout.closeDrawers();
}
}
}
Now you can open the drawer with openDrawer() and close it with closeDrawer().
A sample navigation.xml file which is located under the menu dir in the res (resources) folder:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="#+id/navi_1"
android:checked="true"
android:icon="#drawable/ic_android"
android:title="First item"/>
<item
android:id="#+id/navi_2"
android:icon="#drawable/ic_android"
android:title="Second item"/>
</group>
</menu>
Sample drawer_list_header.xml file, located under the layout dir in the res folder:
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/list_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:paddingBottom="8dp"
android:src="#drawable/list_header_final">
</ImageView>
Here are some notes:
You have to declare a menu file for the drawer, see app:menu="#menu/navigation" in the layout file.
You might want to declare a header layout, which is displayed over the menu elements in the drawer, see app:headerLayout="#layout/drawer_list_header".
The drawer can be opened by a fling-like action from the edge of the screen. To prevent the users from doing that, you might want to lock/unlock your drawer on action using drawerLayout.setDrawerLockMode(...);, see the documentation for details.
Also note that in order to use NavigationView, you'll need the latest design support lib by adding the dependency to your module's gradle file: compile 'com.android.support:design:22.2.0'.
See more about it here.

Yes you can implement DrawerLayout with out ActionBar. You can manually open and close the DrawerLayout like
drawerLayout.openDrawer(Gravity.LEFT);
drawerLayout.closeDrawer(Gravity.LEFT);

Related

(Android) onNavigationItemSelected method not being called

I'm working on an Android app for an Engineering Design project that includes a drawer. One of my group members elected to use the android.support.design.widget.NavigationView API to do this, and it's been causing us some problems. Our MainActivity class implements onNavigationItemSelectedListener, which I understand acts as a listener for the items in the drawer and other navigation bars. The problem is, when one of these navigation items is selected, the onNavigationItemSelected method that has been implemented is not called (I know this because it's supposed to put out a message through LogCat if it is called). All the references I've found for this API suggest that I've done everything right so far, but I've apparently missed something, so any help is appreciated.
Here is the relevant code from the MainActivity class:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpNavComponents();
setUpMapComponents();
PathfinderDataHandler handler = new PathfinderDataHandler();
}
private void setUpNavComponents()
{
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
navigationView.setNavigationItemSelectedListener(this);
}
private void setUpMapComponents()
{
mapFrag = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
mapFrag.getMapAsync(this);
}
#Override
public boolean onNavigationItemSelected(MenuItem item)
{
// Handle navigation view item clicks here.
int id = item.getItemId();
Log.d(null, "onNavigationItemSelected Called");
if (id == R.id.buildings)
{
// Handle the camera action
Log.d(null, "Buildings selected");
}
else if (id == R.id.blue_phones)
{
Log.d(null, "Blue Phones selected");
}
else if (id == R.id.bus_stops)
{
Log.d(null, "Bus Stops selected");
}
else if (id == R.id.pedways)
{
Log.d(null, "Pedways selected");
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Here is the code from activity_main_drawer.xml (Which holds all the items for the drawer)
<?xml version="1.0" encoding="utf-8"?>
<menu 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"
tools:showIn="navigation_view">
<group
android:checkableBehavior="all"
android:enabled="true">
<item
android:id="#+id/buildings"
android:title="#string/building_show_select"
app:actionLayout="#layout/switch_item"
app:showAsAction="always" />
<item
android:id="#+id/blue_phones"
android:title="#string/blue_phone_select"
app:actionLayout="#layout/switch_item"
app:showAsAction="always" />
<item
android:id="#+id/bus_stops"
android:title="#string/bus_stop_select"
app:actionLayout="#layout/switch_item"
app:showAsAction="always" />
<item
android:id="#+id/pedways"
android:title="#string/pedway_select"
app:actionLayout="#layout/switch_item"
app:showAsAction="always" />
</group>
Here is the code for activity_main.xml, which adds the activity_main_drawer to the NavigationView.
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
<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"
app:menu="#menu/activity_main_drawer">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
Another thing to note is that I'm using Switch items instead of regular Menu items.
And before anyone says anything, YES I know this API is depreciated and I should be using NavigationUI in AndroidX, but I don't have time to refactor the app so I have to make do with this.
You have to provide a non null tag for Log.d(String, String), else there will be nothing written to Logcat.
I tried with
Log.d(null, "HelloWorld");
Log.d("TEST", " HelloWorld");
and got only one line in Logcat:

DrawerLayout stops working when fragment back stack is popped

I have a DrawerLayout connected to the ActionBar with an ActionBarDrawerToggle that stops working. I know the question about why it doesn't open has been asked 100 times but my question is a little different. My drawer works! Yep, you click on the hamburger and the drawer opens and closes like a champ...
The problem is that it stops working when I dismiss any fragment that was added to the activity. Here is the activity layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/renderer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/activity_root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
...header stuff...
<ViewStub
android:id="#+id/view_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"/>
...footer stuff...
</RelativeLayout>
<FrameLayout
android:id="#+id/left_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
Then the activity contains this...
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
mRendererLayout = (DrawerLayout) findViewById(R.id.renderer_layout);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mRendererLayout,
R.string.alert_ok,
R.string.cancel_all
) {
#Override
public void onDrawerOpened(View drawerView) {
Log.e("===", "RA.Drawer Opened ");
}
#Override
public void onDrawerClosed(View drawerView) {
Log.e("===", "RA.Drawer Closed ");
}
};
mRendererLayout.addDrawerListener( mDrawerToggle );
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.e("===", "RA.onOptionsItemSelected(): ");
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
At a few points I add various fragments to the activity with
addFragment( new MyFragment() );
Each fragment has a view with an onClick() that calls
getActivity().getSupportFragmentManager().popBackStack();
It is at this point that the drawer stops working. The fragment disappears as expected and it does log "RA.onOptionsItemSelected()" when the hamburger is clicked but "RA.Drawer Opened" is no longer logged and the drawer does not open. This continues until the activity is relaunched.
To make things more complicated the activity uses a ViewStub to swap out two layouts: either a FrameLayout or a FrameLayout containing a ViewPager. Only the latter has the problem. I swap out the viewStub like this...
ViewStub viewStub = findViewById(R.id.view_stub);
viewStub.setLayoutResource(R.layout.either_layout_here);
viewStub.inflate();
Swapping in this layout has no problems with the drawer. It gets a fragment added to it via addFragment():
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Swapping in this layout, on the other hand, has the problem...
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</FrameLayout>
This one does not get a fragment added to its content_frame (yet), since the ViewPager handles its fragments. That's really the only difference. For some reason popping the fragment back stack breaks the drawer button on the ActionBar.
I'm stumped. Help!

How to add a back button to action bar / toolbar

I have written a piece of code as part of an app where I want to implement a back button on the action bar/tool bar such that when the button is pressed, the previous page (the page/fragment immediately before the current page/fragment) will be displayed.
This is the code for the ToolBar, DrawerLayout, NavigationView and getSupportActionBar():
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
final NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setVisibility(View.VISIBLE);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setLogo(R.mipmap.ic_launcher);
getSupportActionBar().setDisplayUseLogoEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
I am unable to use ActionBar. For some reason (I don't know why), my Android studio/ program, will not allow me to use the ActionBar. So I am substituting that with the set/getSupportActionBar().
The function used in relation to this are:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_settings, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch (id) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
My activity_main.xml file is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:fitsSystemWindows="true"
android:id="#+id/activity_main"
android:orientation="vertical"
tools:openDrawer="start"
tools:context="com.example.albin.settings_menu.SettingsActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff">
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:popupTheme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:title="Settings"/>
<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">
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar">
</FrameLayout>
<android.support.design.widget.NavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:layout_marginTop="-24dp"
app:menu="#menu/options_menu" />
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
</LinearLayout>
The problem is that I don't know which is the useful code, which is the useless code and how to mix/join/(add additional codes to) these (codes, methods, variables/objects, fragments, xml layouts) to get the desired outcome, that is, the application of a back button on the action bar/tool bar.
Most of the code above is implemented for the up button, not the back button. I have read at several places that up and back buttons are not the same.
I tried several links on internet as well as on this site, but none of them has just what I need.
Hope someone can give me an clear answer...
You can include the back icon in ToolBar:
Initialize ToolBar:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
You can use an drawable icon as a back button.
toolbar.setNavigationIcon(R.drawable.your_drawable_icon);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// what do you want here
}
});
If you do not want to use drawable icon then:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// what do you want here
}
});
Actually your layout having that issue because you have added toolbar in RelativeLayout so drawer layout is overlapping on it that's why you would not able to click on back arrow, i have fix your layout see below
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:navigationIcon="#drawable/ic_back_black"
app:popupTheme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:title="Settings" />
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/options_menu" />
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
The simplest way would be to add parent activity in manifest file as developer docs suggest.
<activity
android:name=".ChildActivity"
android:parentActivityName=".ParentActivity" >
and java code you already have done it, setSupportActionbar and setHomeAsUpEnabled.
Edited :
its necessary to add up action for icon to be visible, as mentioned in
Android Developer Docs
So toolbar gives added flexibility to modify title-bar in Android.
As far as why getActionBar is not working and you are compelled to use getSupportActionBar is because you must be using SupportLibrary. SupportLibrary gives backward compatibility to earlier SDK versions.
If you want to modify your title-bar/header/action-bar extensively
then use toolbar otherwise use action-bar.
Add a navigation click listener to your toolbar , like below
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
If you are referencing some actions from the action bar, such as a Save action or a Share one, and you are overriding onOptionsItemSelected method, then you need to define the behavior when the back or home button is clicked:
#Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_save:
//save stuff
break;
//this is what you need to add to reference again back/home button
case android.R.id.home:
//do your stuff here, usually back to the home or close the current activity
getActivity().finish();
break;
default:
break;
}
return true;

onNavigationItemSelected not getting called

I have implemented a navigationview in my app , which was automatically created by AndroidStudio. I picked up the NavigationDrawer Activity when I created a new project and the menu items seem ok , but nothing happend when I click on any of the menu item .
Below is my onNavigationItemSelected() method:
#Override
public boolean onNavigationItemSelected(MenuItem item) {
Toast.makeText(MainActivity.this,"onNavigationItemSelected",Toast.LENGTH_LONG).show();
// Handle navigation view item clicks here.
item.setChecked(true);
int id = item.getItemId();
if (id == R.id.medicalRecord) {
Toast.makeText(MainActivity.this,id,Toast.LENGTH_LONG).show();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
And my onCreate method , I create the NavigationView in it
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linear_layout);
if (babyImage.exists()) {
Drawable drawable = Drawable.createFromPath(Environment.getExternalStorageDirectory() + "/babycare/temp.jpg");
linearLayout.setBackground(drawable);
}
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerLayout.openDrawer(Gravity.LEFT);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
Of course , I implemented the NavigationView.OnNavigationItemSelectedListener for my class .
I am wondering whether this NavigationView should be implement in Material Design theme or not . Now the theme used in my app is #style/AppTheme
Please , someone help me out , thank you
I solved my question , just simply change the order in my activity_main.xml .
I have a LinearLayout viewgroup and NavigationView in my DrawerLayout viewgroup , at first the NavigationView is the first in my viewgroup and now I change the order , the first one is the LinearLayout and the second is NavigationView , and it work as it suppose to be . Dear!!!
But can someone tell me why it happend ? Does it matter the view order in a viewgroup regardless the display sequence .
I too had this issue and I finally figured out what was wrong, I initially created a sample project with navigation drawer and the main activity xml was as below,
<include
layout="#layout/app_bar_main"
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"
app:menu="#menu/activity_main_drawer" />
But in the actual app I made I did a mistake like this,
<?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">
<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"
app:menu="#menu/activity_main_drawer" />
<LinearLayout...../>
</android.support.v4.widget.DrawerLayout>
I had a LinearLayout below the NavigationView which was the issue.
Then I did this, everything started to work fine.
<?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">
<LinearLayout...../>
<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"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
Key was to put the NavigationView at last. Weird that UI was not disturbed but callback was.
The Navigation Drawer help say this:
The main content view (the FrameLayout above) must be the first child in the DrawerLayout because the XML order implies z-ordering and the drawer must be on top of the content.
regards to this example:
<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">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
So this is the explanation, what is kind of annoying is if you have the wrong layout order as a result of an auto-generated template. I have faced this kind of "problems" with Android Studio a few times and is so fustrating.
I've just had this problem but none of the answers help me. But finally I solved.
In my case, the listener wasn't called because I used in my activity:
NavigationUI.setupWithNavController(navigationView, navController);
That overrides my OnNavigationItemSelectedListener, so I removed that line and I've setted my listener as the following:
final NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(new
NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
FragmentManager fm = getSupportFragmentManager();
fm.popBackStackImmediate();
boolean handled = NavigationUI.onNavDestinationSelected(item, navController);
if (handled) {
ViewParent parent = navigationView.getParent();
if (parent instanceof DrawerLayout) {
((DrawerLayout) parent).closeDrawer(navigationView);
}
}
return handled;
}
});
Here's a piece of NavigationUI that override my listener:
public static void setupWithNavController(#NonNull final NavigationView navigationView,
#NonNull final NavController navController) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
boolean handled = onNavDestinationSelected(item, navController);
//******* CUTTED ***************
return handled;
}
});
}
I hope it can helps.
The Navigation Drawer help say this:
The main content view (the FrameLayout above) must be the first child in the DrawerLayout because the XML order implies z-ordering and the drawer must be on top of the content.
regards to this example:
<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">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
What is kind of annoying is if you have the wrong layout order as a result of an auto-generated template. I have faced this kind of "problems" with Android Studio a few times and is so fustrating.
you should change the place of tags. shouldn't do NavigationView first. it works.

How to set Navigation Drawer to be opened from right to left

First of all I know this question appeared here before but after trying a lot I still didn't succeed.
I working on the example from
Android Developers site.
I'm trying to set the menu to be opened from right to left instead of how its implementing in the example (from left to right). In addition I want to move the open menu button to the right side of the action bar. I also red some answers here, for example in this answer.
I try to change the gravity of the views and the layouts but I get the error:
no drawer view found with absolute gravity LEFT
Can you please help me to figure out what is the problem in my code and what should I change in order to set the menu to be opened from the right, and to move the action bar button to the right side?
the xml code is here:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_gravity="right"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/content_frame"
android:layoutDirection="rtl"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ListView android:id="#+id/left_drawer"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="10dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
In your main layout set your ListView gravity to right:
android:layout_gravity="right"
Also in your code :
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open,
R.string.drawer_close) {
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null && item.getItemId() == android.R.id.home) {
if (mDrawerLayout.isDrawerOpen(Gravity.RIGHT)) {
mDrawerLayout.closeDrawer(Gravity.RIGHT);
}
else {
mDrawerLayout.openDrawer(Gravity.RIGHT);
}
}
return false;
}
};
hope it works :)
Add this code to manifest:
<application android:supportsRtl="true">
and then write this code on Oncreate:
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
It works for me. ;)
SOLUTION
your_layout.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="end">
<include layout="#layout/app_bar_root"
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="end"
android:fitsSystemWindows="true"
app:itemTextColor="#color/black"
app:menu="#menu/activity_root_drawer" />
</android.support.v4.widget.DrawerLayout>
YourActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
toolbar = (Toolbar) findViewById(R.id.toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawer.isDrawerOpen(Gravity.RIGHT)) {
drawer.closeDrawer(Gravity.RIGHT);
} else {
drawer.openDrawer(Gravity.RIGHT);
}
}
});
//...
}
This answer is useful to set the navigation be open from right to left, but it has no solution to set its icon to be right side. This code can fix it. If you give it the drawer as its first param and ViewCompat.LAYOUT_DIRECTION_RTL as its second param, the entier layout will be set to RTL. It is a quick and simple solution, but I don't think it can be a correct solution for who that want to only set the menu to be opened from right to left and set its icon to be on right side. (Although, it's depended to your purpose.) However, I suggest giving the toolbar instead of the drawer. In this way just the toolbar has become RTL. So I think the combination of these 2 answers can exactly do what you want.
According to these descriptions, your code should be like this:
(Add these lines to onCreate method)
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); // Set it final to fix the error that will be mention below.
ViewCompat.setLayoutDirection(toolbar, ViewCompat.LAYOUT_DIRECTION_RTL);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawer.isDrawerOpen(Gravity.RIGHT))
drawer.closeDrawer(Gravity.RIGHT);
else
drawer.openDrawer(Gravity.RIGHT);
}
});
Notice that you should make drawer final, otherwise you will get this error:
Variable 'drawer' is accessed from within inner class, needs to be
declared final
And don't forget to use end instead of start in onNavigationItemSelected method:
drawer.closeDrawer(GravityCompat.END);
and in your activity_main.xml
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
tools:openDrawer="end">
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_gravity="end"/>
</android.support.v4.widget.DrawerLayout>
Here is the documentation on the drawer and it appears that you can configure it to pull out from the left or right.
Drawer positioning and layout is controlled using the android:layout_gravity attribute on child views corresponding to which side of the view you want the drawer to emerge from: left or right. (Or start/end on platform versions that support layout direction.)
http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.html
Take a look at this: slide ExpandableListView at DrawerLayout form right to left
I assume you have the ActionBarDrawerToggle implemented, the trick is to override the onOptionsItemSelected(MenuItem item) method inside the ActionBarDrawerToggle object with this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null && item.getItemId() == android.R.id.home) {
if (mDrawer.isDrawerOpen(Gravity.RIGHT)) {
mDrawer.closeDrawer(Gravity.RIGHT);
} else {
mDrawer.openDrawer(Gravity.RIGHT);
}
return true;
}
return false;
}
make sure and call this from onOptionsItemSelected(MenuItem item) in the Activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
This will allow you to use the the home button functionality. To move the button to the right side of the action bar you will have to implement a custom action item, and maybe some other stuff to get it to work like you want.
the main issue with the following error:
no drawer view found with absolute gravity LEFT
is that, you defined the
android:layout_gravity="right"
for list-view in right, but try to open the drawer from left, by calling this function:
mDrawerToggle.syncState();
and clicking on hamburger icon!
just comment the above function and try to handle open/close of menu like #Rudi said!
I have solved this problem by changing the gravity of the navigationview
android:layout_gravity
to end instead of start
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/activity_drawer" />
It worked for me.
You should firstly put this code in your AppManifest.xml in the application tag:
android:supportsRtl="true"
then in your activity_main.xml file, put this piece of code:
android:layout_direction="rtl"
I did following modification to the Navigation Drawer Activity example in Android Studio. With support libraries 25.3.1.
MainActivity.java:
private DrawerLayout mDrawerLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.END)) {
mDrawerLayout.closeDrawer(GravityCompat.END);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
finish();
return true;
case R.id.action_right_drawer:
if (mDrawerLayout.isDrawerOpen(GravityCompat.END)) {
mDrawerLayout.closeDrawer(GravityCompat.END);
} else {
mDrawerLayout.openDrawer(GravityCompat.END);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
mDrawerLayout.closeDrawer(GravityCompat.END);
return true;
}
main.xml (download ic_menu_white_24px from https://material.io/icons/):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_right_drawer"
android:title="Drawer menu"
android:icon="#drawable/ic_menu_white_24px"
android:orderInCategory="100"
app:showAsAction="always" />
</menu>
In activity_main.xml change
android:layout_gravity="start"
to
android:layout_gravity="end"
Making it open from rtl isn't good for user experience, to make it responsive to the user locale I just added the following line to my DrawerLayout parameters:
android:layoutDirection="locale"
Added it to my AppBarLayout to make the hamburger layout match the drawer opening direction too.
DrawerLayout Properties
android:layout_gravity="right|end" and tools:openDrawer="end"
NavigationView Property
android:layout_gravity="end"
XML Layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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"
android:layout_gravity="right|end"
tools:openDrawer="end">
<include layout="#layout/content_main" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
Java Code
// Appropriate Click Event or Menu Item Click Event
if (drawerLayout.isDrawerOpen(GravityCompat.END))
{
drawerLayout.closeDrawer(GravityCompat.END);
}
else
{
drawerLayout.openDrawer(GravityCompat.END);
}
//With Toolbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Gravity.END or Gravity.RIGHT
if (drawer.isDrawerOpen(Gravity.END)) {
drawer.closeDrawer(Gravity.END);
} else {
drawer.openDrawer(Gravity.END);
}
}
});
//...
}
In your layout file inside NavigationView set this attribute android:layout_gravity="end" and set tools:openDrawer="end" in the DrawerLayout
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".tasks.TasksActivity"
android:id="#+id/drawer_layout"
tools:openDrawer="end">
<!-- Navigation Drawer -->
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/drawer_actions" />
</androidx.drawerlayout.widget.DrawerLayout>
Output
I know this is an old question, but I've been struggling with this problem for a few days now and finally achived the solution.
If you want to use the default new project "Navigation Drawer Activity" to work with a drawer from right to left:
Create a custom DrawerLayout class:
public class CustomDrawerLayout extends DrawerLayout {
public CustomDrawerLayout(#NonNull Context context) {
super(context);
}
public CustomDrawerLayout(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomDrawerLayout(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void open() {
openDrawer(GravityCompat.END);
}
#Override
public void close() {
closeDrawer(GravityCompat.END);
}
#Override
public boolean isOpen() {
return isDrawerOpen(GravityCompat.END);
}
}
On activity_main.xml:
set DrawerLayout tools:openDrawer="end"
set NavigationView android:layout_gravity="end"
change tag view from androidx.drawerlayout.widget.DrawerLayout to your CustomDrawerLayout com.example.CustomDrawerLayout
If you create new menu options, it is important that the id of the item in menu/activity_main_drawer.xml is the same as the id of the fragment in navigation/mobile_navigation.xml.
Summarising multiple answers into one which worked for me.
Following were my requirements
1. Align navigation drawer hamburger icon to write
2. Start the navigation drawer from right to left
3. Achieve the above two points without changing the direction to rtl of the whole layout
To start the Navigation drawer from right to left
Set DrawerLayout tools:openDrawer="end"
Set NavigationView android:layout_gravity="end"
mDrawerToggle.setToolbarNavigationClickListener {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.END)) {
binding.drawerLayout.closeDrawer(GravityCompat.END)
} else {
binding.drawerLayout.openDrawer(GravityCompat.END)
}
}
To set the Hamburger menu to the right
Set AppBarLayout android:layoutDirection="rtl"

Categories

Resources