Change Floating Action Button Image Programmatically in DrawerLayout - android

Just as the title suggest, I am trying to change the floating image button's icon/image programmatically when the user open specifics fragment from DrawerLayout. This is what I've alredy tried : First, this is the onCreate() method for the DrawerLayout class.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu_drawer);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), TransaksiKeranjang.class);
startActivity(intent);
}
});
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_transaksi, R.id.nav_pesanan, R.id.nav_sejarah, R.id.nav_inventory,
R.id.nav_akun, R.id.nav_cabang, R.id.nav_laporan, R.id.nav_logout)
.setDrawerLayout(drawer)
.build();
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
//Change fab icon when branch fragment open
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
#Override
public void onDestinationChanged(#NonNull NavController controller, #NonNull NavDestination destination, #Nullable Bundle arguments) {
if (destination.getId() == R.id.nav_cabang) {
fab.setImageDrawable(ContextCompat.getDrawable(getParent(), R.drawable.icon_add));
}
}
});
navigationView.getMenu().findItem(R.id.nav_logout).setOnMenuItemClickListener(menuItem -> {
Intent intent = new Intent(MenuDrawer.this, Login.class);
startActivity(intent);
return true;
});
}
And then this is the xml where floating action button exist :
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/background_fragment"
tools:context=".MenuDrawer">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/Theme.HuwenakApp.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/huwenak_brown"
app:popupTheme="#style/Theme.HuwenakApp.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/content_main" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/icon_cart" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
The problem is when I try to change the fab image I always get a nullPointerException error in this line :
fab.setImageDrawable(ContextCompat.getDrawable(getParent(), R.drawable.icon_add));
Which is weird because the onClickListener is working fine and not giving me this error.

You have to add the context
fab.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.icon_add))
You see in documentation getDrawable need context and if you pass the parent then you get the below error
Attempt to invoke virtual method 'android.graphics.drawable.Drawable android.content.Context.getDrawable(int)' on a null object reference
getDrawable(#NonNull Context context, #DrawableRes int id)

Related

(Navigation component) How to display back arrow on the activity when back to the home fragment?

I have to fragments discount fragment and edit service fragment displayed on Edit Service activity.
the back arrow displayed on discount fragment when i back to edit service fragment the arrow disappear i want to display it to navigate the previous activity from edit service activity.
activity layout
.........................................................
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar_hesham"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:title="#string/edit_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent" />
<fragment
android:id="#+id/nav_host_edit_service"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#+id/toolbar_hesham"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="#navigation/edit_service_nav" />
</androidx.constraintlayout.widget.ConstraintLayout>
<include layout="#layout/confirm_request_bottom_sheet"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
activity code
.............................................................
public class EditServicesActivity extends BaseActivity<MainViewModel> {
public Toolbar toolbar;
public NavController navController;
#Override
protected void initActivityComponent() {
component = ProServeTechApp.getComponent(this)
.plus(new ActivityModule(this));
component.inject(this);
}
#Override
protected int getLayout() {
return R.layout.activity_edit_services;
}
#Override
protected Class<MainViewModel> getViewModelClass() {
return MainViewModel.class;
}
#Override
protected void initActivity() {
viewModel.getRequestDetails(getIntent().getExtras().getString("requestId"), String.valueOf(0));
viewModel.getIssues(getIntent().getStringExtra("requestId"));
toolbar = findViewById(R.id.toolbar_hesham);
setSupportActionBar(toolbar);
navController = Navigation.findNavController(this, R.id.nav_host_edit_service);
NavigationUI.setupWithNavController(toolbar, navController );
}
}
navigation
........................................
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/edit_service_nav"
app:startDestination="#id/edi_service_fragment">
<fragment
android:id="#+id/edi_service_fragment"
android:name="com.unicomg.proservetech.ui.requestdetails.edit.service.fragments.EditServiceFragment"
android:label="#string/edit_service"
tools:layout="#layout/edit_service_fragment">
<action
android:id="#+id/action_edi_service_fragment_to_discount_fragment"
app:destination="#id/discount_fragment"
app:enterAnim="#anim/slide_up"
app:exitAnim="#anim/slide_bottom"
app:popEnterAnim="#anim/slide_up"
app:popExitAnim="#anim/slide_bottom" />
</fragment>
<fragment
android:id="#+id/discount_fragment"
android:name="com.unicomg.proservetech.ui.requestdetails.edit.service.fragments.DiscountFragment"
android:label="#string/add_discount"
tools:layout="#layout/discount_fragment">
</fragment>
</navigation>
As per the setupWithNavController(Toolbar, NavController) documentation:
The start destination of your navigation graph is considered the only top level destination. On all other destinations, the Toolbar will show the Up button.
If you want to also show the Up button on your start destination (i.e., to go to the previous activity), you'd want to use the version that takes an AppBarConfiguration.
As per the Update UI components documentation on AppBarConfiguration, AppBarConfiguration allows you to set exactly what destinations you want as top level destinations. To get the Up button to show on every destination, you'd use an empty set of top level destinations:
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder().build();
Note that since you're using setSUpportActionBar(), you should follow the Action Bar documentation and use the setupActionBarWithNavController() method rather than the Toolbar version. You must also override onSupportNavigateUp() to handle the up button.
Therefore your complete code would look like:
public class EditServicesActivity extends BaseActivity<MainViewModel> {
public Toolbar toolbar;
public AppBarConfiguation appBarConfiguation;
public NavController navController;
#Override
protected void initActivityComponent() {
component = ProServeTechApp.getComponent(this)
.plus(new ActivityModule(this));
component.inject(this);
}
#Override
protected int getLayout() {
return R.layout.activity_edit_services;
}
#Override
protected Class<MainViewModel> getViewModelClass() {
return MainViewModel.class;
}
#Override
protected void initActivity() {
viewModel.getRequestDetails(getIntent().getExtras().getString("requestId"), String.valueOf(0));
viewModel.getIssues(getIntent().getStringExtra("requestId"));
toolbar = findViewById(R.id.toolbar_hesham);
setSupportActionBar(toolbar);
navController = Navigation.findNavController(this, R.id.nav_host_edit_service);
appBarConfiguration = new AppBarConfiguration.Builder().build();
NavigationUI.setupActionBarWithNavController(this, navController,
appBarConfiguration);
}
#Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(navController, appBarConfiguration)
|| super.onSupportNavigateUp();
}
}

No drawer view found with gravity LEFT - Android

My menu was opening from left to right, but I want it to be opened from right to left. I have arranged the code to be opened from right to left, but now the code does not work I get the following error.
java.lang.IllegalArgumentException: No drawer view found with gravity LEFT
I get an error on this line : return NavigationUI.navigateUp(navController, mAppBarConfiguration)
MAİN CLASS
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
NavigationView navigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_sss, R.id.nav_gelisim,
R.id.nav_destek,R.id.nav_hakkımızda,R.id.nav_instagram)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
}
XML
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layoutDirection="rtl"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:itemTextColor="#color/white"
app:itemTextAppearance="#style/NavDrawerTextStyle"
android:layout_gravity="right"
android:theme="#style/NavigationView"
android:background="#color/NavItem"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main2"
app:menu="#menu/activity_main_drawer"/>
</androidx.drawerlayout.widget.DrawerLayout>
You need to handle navigation click on Toolbar like below:
ViewCompat.setLayoutDirection(toolbar, ViewCompat.LAYOUT_DIRECTION_RTL);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawer.isDrawerOpen(GravityCompat.END))
drawer.closeDrawer(GravityCompat.END);
else
drawer.openDrawer(GravityCompat.END);
}
});
Also don't forgot to close drawer whenever needed like below:
drawer.closeDrawer(GravityCompat.END)
You could possible find your answer here in this previous post:
Android DrawerLayout - No drawer view found with gravity
You have to set layout Direction in Your Root Drawer Layout
android:layoutDirection="rtl"
If you set the layout direction of the root drawer as follows:
android:layoutDirection="rtl"
All elements will change direction. To solve this, place all elements within a LinearLayout and set LinearLayout direction to ltr.
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
**android:layoutDirection="rtl"**
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
**android:layoutDirection="ltr"**>
<!--place your layout here-->
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layoutDirection="rtl"
app:menu="#menu/drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
If you are using the navigation component use the below code in your activity class.
override fun onCreate(savedInstanceState: Bundle?) {
//...
val navHostFragment = supportFragmentManager.findFragmentById(
R.id.my_nav_host_fragment
) as NavHostFragment
navController = navHostFragment.navController
binding.navigationView.setupWithNavController(navController)
//...
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController, binding.drawerLayout)
}
override fun onBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
It seems like the DrawerLayout need to be in the start direction every time,
if you want it to open from the left you need to do the following:
make your DrawerLayout android:layoutDirection="ltr"
remove tools:openDrawer from your DrawerLayout XML
put your NaviagtionView android:layout_gravity="start"
if you want your content to be RTL don't forget to do this in your contentView container android:layoutDirection="rtl"
and it will work like a charm!

Back arrow in tool bar in order to go to previous activity [duplicate]

I'm migrating from ActionBar to Toolbar in my application.
But I don't know how to display and set click event on Back Arrow on Toolbar like I did on Actionbar.
With ActionBar, I call mActionbar.setDisplayHomeAsUpEnabled(true).
But there is no the similar method like this.
Has anyone ever faced this situation and somehow found a way to solve it?
If you are using an ActionBarActivity then you can tell Android to use the Toolbar as the ActionBar like so:
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
setSupportActionBar(toolbar);
And then calls to
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
will work. You can also use that in Fragments that are attached to ActionBarActivities you can use it like this:
((ActionBarActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((ActionBarActivity) getActivity()).getSupportActionBar().setDisplayShowHomeEnabled(true);
If you are not using ActionBarActivities or if you want to get the back arrow on a Toolbar that's not set as your SupportActionBar then you can use the following:
mActionBar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_action_back));
mActionBar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//What to do on back clicked
}
});
If you are using android.support.v7.widget.Toolbar, then you should add the following code to your AppCompatActivity:
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
I see a lot of answers but here is mine which is not mentioned before. It works from API 8+.
public class DetailActivity extends AppCompatActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// add back arrow to toolbar
if (getSupportActionBar() != null){
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle arrow click here
if (item.getItemId() == android.R.id.home) {
finish(); // close this activity and return to preview activity (if there is any)
}
return super.onOptionsItemSelected(item);
}
There are many ways to achieve that, here is my favorite:
Layout:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="?attr/homeAsUpIndicator" />
Activity:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// back button pressed
}
});
you can use the tool bar setNavigationIcon method.
Android Doc
mToolBar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
handleOnBackPress();
}
});
If you don't want to create a custom Toolbar, you can do like this
public class GalleryActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
...
getSupportActionBar().setTitle("Select Image");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
}
In you AndroidManifest.xml
<activity
android:name=".GalleryActivity"
android:theme="#style/Theme.AppCompat.Light">
</activity>
you can also put this android:theme="#style/Theme.AppCompat.Light" to <aplication> tag, for apply to all activities
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setNavigationIcon(R.drawable.back_arrow); // your drawable
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed(); // Implemented by activity
}
});
And for API 21+ android:navigationIcon
<android.support.v7.widget.Toolbar
android:navigationIcon="#drawable/back_arrow"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
I used this method from the Google Developer Documentation:
#Override
public void onCreate(Bundle savedInstanceState) {
...
getActionBar().setDisplayHomeAsUpEnabled(true);
}
If you get a null pointer exception it could depend on the theme. Try using a different theme in the manifest or use this alternatively:
#Override
public void onCreate(Bundle savedInstanceState) {
...
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Then in the manifest, where I set the parent activity for current activity:
<activity
android:name="com.example.myapp.MyCurrentActivity"
android:label="#string/title_activity_display_message"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myapp.MyMainActivity" />
</activity>
I hope this will help you!
If you were using AppCompatActivity and have gone down the path of not using it, because you wanted to not get the automatic ActionBar that it provides, because you want to separate out the Toolbar, because of your Material Design needs and CoordinatorLayout or AppBarLayout, then, consider this:
You can still use the AppCompatActivity, you don't need to stop using it just so that you can use a <android.support.v7.widget.Toolbar> in your xml. Just turn off the action bar style as follows:
First, derive a style from one of the NoActionBar themes that you like in your styles.xml, I used Theme.AppCompat.Light.NoActionBar like so:
<style name="SuperCoolAppBarActivity" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/primary</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#color/primary_dark</item>
...
...
</style>
In your App's manifest, choose the child style theme you just defined, like so:
<activity
android:name=".activity.YourSuperCoolActivity"
android:label="#string/super_cool"
android:theme="#style/SuperCoolAppBarActivity">
</activity>
In your Activity Xml, if the toolbar is defined like so:
...
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
/>
...
Then, and this is the important part, you set the support Action bar to the AppCompatActivity that you're extending, so that the toolbar in your xml, becomes the action bar. I feel that this is a better way, because you can simply do the many things that ActionBar allows, like menus, automatic activity title, item selection handling, etc. without resorting to adding custom click handlers, etc.
In your Activity's onCreate override, do the following:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_super_cool);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//Your toolbar is now an action bar and you can use it like you always do, for example:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
If your are using the androidx.appcompat.app.AppCompatActivity just use:
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Then just define in the Manifest.xml the parent Activity.
<activity
android:name=".MyActivity"
...>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ParentActivity" />
</activity>
Instead if you are using a Toolbar and you want a custom behavior just use:
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
app:navigationIcon="?attr/homeAsUpIndicator"
.../>
and in your Activity:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//....
}
});
In Kotlin it would be
private fun setupToolbar(){
toolbar.title = getString(R.string.YOUR_TITLE)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
}
// don't forget click listener for back button
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
Simple and easy way to show back button on toolbar
Paste this code in onCreate method
if (getSupportActionBar() != null){
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
Paste this override method outside the onCreate method
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()== android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
MyActivity extends AppCompatActivity {
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
toolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(arrow -> onBackPressed());
}
Easily you can do it.
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
Credits:
https://freakycoder.com/android-notes-24-how-to-add-back-button-at-toolbar-941e6577418e
First, you need to initialize the toolbar :
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
then call the back button from the action bar :
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
In the AppCompatActivity for example you can do
public class GrandStatActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grand_stat);
}
#Override
public void onResume() {
super.onResume();
// Display custom title
ActionBar actionBar = this.getSupportActionBar();
actionBar.setTitle(R.string.fragment_title_grandstats);
// Display the back arrow
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
// Back arrow click event to go to the parent Activity
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
In your manifest file for the activity where you want to
add a back button, we will use the property android:parentActivityName
<activity
android:name=".WebActivity"
android:screenOrientation="portrait"
android:parentActivityName=".MainActivity"
/>
P.S. This attribute was introduced in API Level 16.
If you want to get the back arrow on a Toolbar that's not set as your SupportActionBar:
(kotlin)
val resId = getResIdFromAttribute(toolbar.context, android.R.attr.homeAsUpIndicator)
toolbarFilter.navigationIcon = ContextCompat.getDrawable(toolbar.context, resId)
toolbarFilter.setNavigationOnClickListener { fragmentManager?.popBackStack() }
to get res from attributes:
#AnyRes
fun getResIdFromAttribute(context: Context, #AttrRes attr: Int): Int {
if (attr == 0) return 0
val typedValueAttr = TypedValue()
context.theme.resolveAttribute(attr, typedValueAttr, true)
return typedValueAttr.resourceId
}
This worked perfectly
public class BackButton extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_box);
Toolbar chatbox_toolbar=(Toolbar)findViewById(R.id.chat_box_toolbar);
chatbox_toolbar.setTitle("Demo Back Button");
chatbox_toolbar.setTitleTextColor(getResources().getColor(R.color.white));
setSupportActionBar(chatbox_toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
chatbox_toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Define Back Button Function
}
});
}
}
Follow 3 steps if you want to handle your problem fastly & simply:
Add file ic_arrow.xml to Drawable folder with some codes below (add codes below into ic_arrow.xml)
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="24dp"
android:height="24dp"
android:tint="#color/black"
android:viewportWidth="24"
android:viewportHeight="24"
tools:ignore="ExtraText">
<path
android:fillColor="#android:color/white"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
</vector>
Add ImageButton to Toolbar (make sure the Toolbar customized, not Titlebar or Statusbar) - You can customize the ImageButton (arrow button) position if you want
<ImageButton
android:id="#+id/arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_arrow"
android:layout_marginTop="15dp"
android:layout_marginStart="15dp"
android:background="#android:color/transparent"
tools:ignore="ContentDescription" />
Add the setArrowButton method to DetailActivity.java (or any xxxActivity.java that you need)
public class DetailActivity extends AppCompatActivity {
ImageButton arrowButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
arrowButton = findViewById(R.id.arrow);
setArrowButton(arrowButton);
}
public void setArrowButton(ImageButton arrowButton) {
arrowButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish(); //will close the moment activity and return to
//the last activity
}
});
}
}
Done
Preview about arrowButton
Add this to activity's xml in layout folder:
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/prod_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
Make toolbar clickable, add these to onCreate method:
Toolbar toolbar = (Toolbar) findViewById(R.id.prod_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
With Kotlin it became:
Xml:
<include
android:id="#+id/tbSignToolbar "
layout="#layout/toolbar_sign_up_in"/>
In your Activity:-
setSupportActionBar(tbSignToolbar as Toolbar?)//tbSignToolbar :id of your toolbar
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
Possibly a more reliable way to get the up icon from your theme (if not using the toolbar as your action bar):
toolbar.navigationIcon = context.getDrawableFromAttribute(R.attr.homeAsUpIndicator)
In order to turn the theme attribute into a drawable I used an extension function:
fun Context.getDrawableFromAttribute(attributeId: Int): Drawable {
val typedValue = TypedValue().also { theme.resolveAttribute(attributeId, it, true) }
return resources.getDrawable(typedValue.resourceId, theme)
}
If you are using DrawerLayout with ActionBarDrawerToggle, then to show Back button instead of Menu button (and viceversa), you need to add this code in your Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.application_name, R.string.application_name);
mDrawerLayout.addDrawerListener(mDrawerToggle);
mDrawerToggle.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_32dp);
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onBackPressed(); // Or you can perform some other action here when Back button is clicked.
}
});
mDrawerToggle.syncState();
// ...
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item))
return true;
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
// ...
}
return super.onOptionsItemSelected(item);
}
public void showBackInToolbar(boolean isBack) {
// Remove next line if you still want to be able to swipe to show drawer menu.
mDrawerLayout.setDrawerLockMode(isBack ? DrawerLayout.LOCK_MODE_LOCKED_CLOSED : DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerToggle.setDrawerIndicatorEnabled(!isBack);
mDrawerToggle.syncState();
}
So when you need to show Back button instead of Menu button, call showBackInToolbar(true), and if you need Menu button, call showBackInToolbar(false).
You can generate back arrow (ic_arrow_back_white_32dp) over here, search arrow_back in Clipart section (use default 32dp with 8dp padding). Just select the color you want.
You can always add a Relative layout or a Linear Layout in your Toolbar and place a Image view for back icon or close icon anywhere in toolbar as you like
For example I have used Relative layout in my toolbar
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_top"
android:layout_width="match_parent"
android:layout_height="35dp"
android:minHeight="?attr/actionBarSize"
android:nextFocusDown="#id/netflixVideoGridView"
app:layout_collapseMode="pin">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Myflix"
android:textAllCaps="true"
android:textSize="19sp"
android:textColor="#color/red"
android:textStyle="bold" />
<ImageView
android:id="#+id/closeMyFlix"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
app:srcCompat="#drawable/vector_close" />
</RelativeLayout>
</android.support.v7.widget.Toolbar>
And it looks like this:
You can add click listener on that image view from Activity or fragment like this.
closeMyFlix.setOnClickListener({
Navigator.instance.showFireTV( activity!!.supportFragmentManager)
})
If you are using JetPack Navigation.
Here is the layout for MainActivity
<androidx.constraintlayout.widget.ConstraintLayout 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">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolBar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.appcompat.widget.Toolbar>
<fragment
android:id="#+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintTop_toBottomOf="#id/toolBar"
app:layout_constraintBottom_toTopOf="parent"
app:navGraph="#navigation/nav_graph"/>
SetUp your toolbar in your activity like below in onCreate() of your Activity class.
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment? ?: return
val navController = navHostFragment.findNavController()
val toolBar = findViewById<Toolbar>(R.id.toolBar)
setSupportActionBar(toolBar) // To set toolBar as ActionBar
setupActionBarWithNavController(navController)
setupActionBarWithNavController(navController) Will create a back button on the toolBar if needed and handles the backButton functionality.
If you need to write a CustomBack functionality, create a callBack as below on your fragment onCreate() method
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// Handle the back button event
}
From Documentation:https://developer.android.com/guide/navigation/navigation-custom-back
maybe it will help someone,I didn't find in the answares the thing I did by the end:
with ActionBarDrawerToggle mDrawerToggle;
to show the back arrow in toolbar set:
mDrawerToggle.setDrawerIndicatorEnabled(false);
and if you want it to show the hamburger in the toolbar:
mDrawerToggle.setDrawerIndicatorEnabled(true);

BottomAppBar with BottomNavigationDrawer connected to NavigationController

Hi I'm trying to use new arch components in my project. Short description what I want to achieve:
When user is on MainFragment I want to display navigation icon (Hamburger) on BottomAppBar. User is able to click navigation icon and display BottomNavigationDrawer
When user select some menu item, or click something on MainFragment he is moved to another fragment, let say DebtDetailsFragment. Then Hamburger should be replaced with 'Back arrow' by NavigationController
Below I pasted my MainActivity code. When I comment line with navigation controller, the Hamburger icon is visible and BottomNavigationDrawer is able to display.
But when I uncomment this line, the Hamburger disappear because NavigationController knows nothing about NavigationView used in BottomNavigationDrawer. I don't use DrawerLayout, so controller thinks Hamburger is not needed.
Method setupWithNavController can control Hamburger icon and back arrow, but I have to provide DrawerLayout as parameter which I don't use.
Documentation for this method:
The Toolbar will also display the Up button when you are on a non-root destination and the drawer icon when on the root destination, automatically animating between them. This method will call [DrawerLayout.navigateUp] when the navigation icon is clicked.
So the question is, how to display Hamburger icon when NavigationController is connected with BottomAppBar but without DrawerLayout? I will handle hamburger click myself in onOptionsItemSelected method.
class MainActivity : BaseActivity() {
#Inject
lateinit var viewModelProvider: ViewModelProvider.Factory
private val viewModel: MainActivityViewModel by lazy {
ViewModelProviders.of(this, viewModelProvider).get(MainActivityViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(bottomAppBar)
val navController = findNavController(R.id.main_nav_host_fragment)
//bottomAppBar.setupWithNavController(navController)
onDestroyDisposables += viewModel.uiStateObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(::render, Timber::e)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.bottomappbar_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
android.R.id.home -> {
val bottomNavDrawerFragment = BottomNavigationDrawerFragment()
bottomNavDrawerFragment.show(supportFragmentManager, bottomNavDrawerFragment.tag)
}
}
return super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.main_nav_host_fragment).navigateUp()
}
}
Without setted Navigation controller:
BottomNavigationDrawer
With setted NavigationController - Hamburger invisible.
The BottomAppBar should never display an Up button as per the anatomy of the BottomAppBar - it should only ever display the drawer icon. As seen in the behavior documentation, the Up button should be displayed in a top Toolbar.
Therefore, you should never be calling bottomAppBar.setupWithNavController(navController), but instead calling setupWithNavController(navController) using whatever top Toolbar you have.
To set up your BottomAppBar, you should instead set your own drawer icon and handle clicks on the drawer icon yourself.
The DrawerArrowDrawable class is available to give you a correct drawer icon:
val icon = DrawerArrowDrawable(bottomAppBar.context)
bottomAppBar.navigationIcon = icon
I implemented the BottomAppBar with Jetpack navigation drawer component as following way in my app.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomAppBar bottomAppBar = findViewById(R.id.bottomAppBar);
setSupportActionBar(bottomAppBar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
NavigationView navigationView = findViewById(R.id.nav_view);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
return NavigationUI.navigateUp(navController, drawer)
|| super.onSupportNavigateUp();
}
}
activity_main.xml
<?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"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.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" />
</androidx.drawerlayout.widget.DrawerLayout>
app_bar_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<include layout="#layout/content_main" />
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:layout_gravity="bottom"
app:fabCradleVerticalOffset="16dp"
app:navigationIcon="#drawable/ic_baseline_menu_24"
app:navigationContentDescription="#string/nav_header_desc"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
style="#style/Widget.MaterialComponents.BottomAppBar.Colored"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_menu_send"
app:layout_anchor="#id/bottomAppBar"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
The result will be like this

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