ActionBarDrawerToggle right side on android with navigation view [duplicate] - java

My requirement is shown in the picture below My navigation drawer should be opened from the right side. I have implemented this. My navigation drawer open from right to left. But the problem is toggle icon is always on the left side. How can I set toggle icon to the right?
I have checked the following SO questions, but none of them came to any help:
Change toggle button image Icon In Navigation Drawer right to left
Drawer Toggle in right Drawer
enter link description here
Here is what I have tried:
code for my layout activity_main.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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="end">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.nav.MainActivity"
android:foregroundGravity="right">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:layout_gravity="right"
app:popupTheme="#style/AppTheme.PopupOverlay"
android:foregroundGravity="right"
android:textAlignment="viewEnd"
android:touchscreenBlocksFocus="false" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="end"
app:headerLayout="#layout/nav_header"
app:menu="#menu/menu_navigation"
android:textAlignment="viewEnd" />
</android.support.v4.widget.DrawerLayout>
Code for my activity
public class MainActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initNavigationDrawer();
}
#TargetApi(Build.VERSION_CODES.M)
public void initNavigationDrawer() {
NavigationView navigationView = (NavigationView)findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
int id = menuItem.getItemId();
switch (id){
case R.id.home:
Toast.makeText(getApplicationContext(),"Home",Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawers();
break;
case R.id.settings:
Toast.makeText(getApplicationContext(),"Settings",Toast.LENGTH_SHORT).show();
break;
case R.id.trash:
Toast.makeText(getApplicationContext(),"Trash",Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawers();
break;
case R.id.logout:
finish();
}
return true;
}
});
drawerLayout = (DrawerLayout)findViewById(R.id.drawer);
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.drawer_open,R.string.drawer_close){
#Override
public void onDrawerClosed(View v){
super.onDrawerClosed(v);
}
#Override
public void onDrawerOpened(View v) {
super.onDrawerOpened(v);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null && item.getItemId() == android.R.id.home) {
if (drawerLayout.isDrawerOpen(Gravity.RIGHT)) {
drawerLayout.closeDrawer(Gravity.RIGHT);
}
else {
drawerLayout.openDrawer(Gravity.RIGHT);
}
}
return false;
}
};
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawerLayout.isDrawerOpen(Gravity.RIGHT)) {
drawerLayout.closeDrawer(Gravity.RIGHT);
} else {
drawerLayout.openDrawer(Gravity.RIGHT);
}
}
});
}
}

There's really no (practical) way to make ActionBarDrawerToggle do that, as it is always set on the start/left-side navigation button. However, that class is basically just a DrawerListener that manages a specialized Drawable, and wires an ImageButton to the DrawerLayout. We can put together something similar for an end/right-side drawer with an ImageButton that we can place on that same side in a Toolbar (which is required for this example).
public class EndDrawerToggle implements DrawerLayout.DrawerListener {
private final DrawerLayout drawerLayout;
private final AppCompatImageButton toggleButton;
private final int openDrawerContentDescRes;
private final int closeDrawerContentDescRes;
private DrawerArrowDrawable arrowDrawable;
public EndDrawerToggle(DrawerLayout drawerLayout, Toolbar toolbar,
int openDrawerContentDescRes, int closeDrawerContentDescRes) {
this.drawerLayout = drawerLayout;
this.openDrawerContentDescRes = openDrawerContentDescRes;
this.closeDrawerContentDescRes = closeDrawerContentDescRes;
toggleButton = new AppCompatImageButton(toolbar.getContext(), null,
R.attr.toolbarNavigationButtonStyle);
toolbar.addView(toggleButton, new Toolbar.LayoutParams(GravityCompat.END));
toggleButton.setOnClickListener(v -> toggle());
loadDrawerArrowDrawable();
}
public void syncState() {
if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
setPosition(1f);
} else {
setPosition(0f);
}
}
public void onConfigurationChanged(Configuration newConfig) {
loadDrawerArrowDrawable();
syncState();
}
#Override
public void onDrawerSlide(#NonNull View drawerView, float slideOffset) {
setPosition(Math.min(1f, Math.max(0f, slideOffset)));
}
#Override
public void onDrawerOpened(#NonNull View drawerView) {
setPosition(1f);
}
#Override
public void onDrawerClosed(#NonNull View drawerView) {
setPosition(0f);
}
#Override
public void onDrawerStateChanged(int newState) {}
private void loadDrawerArrowDrawable() {
arrowDrawable = new DrawerArrowDrawable(toggleButton.getContext());
arrowDrawable.setDirection(DrawerArrowDrawable.ARROW_DIRECTION_END);
toggleButton.setImageDrawable(arrowDrawable);
}
private void toggle() {
final int drawerLockMode = drawerLayout.getDrawerLockMode(GravityCompat.END);
if (drawerLayout.isDrawerVisible(GravityCompat.END)
&& (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
drawerLayout.closeDrawer(GravityCompat.END);
} else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
drawerLayout.openDrawer(GravityCompat.END);
}
}
private void setPosition(float position) {
if (position == 1f) {
arrowDrawable.setVerticalMirror(true);
setContentDescription(closeDrawerContentDescRes);
} else if (position == 0f) {
arrowDrawable.setVerticalMirror(false);
setContentDescription(openDrawerContentDescRes);
}
arrowDrawable.setProgress(position);
}
private void setContentDescription(int resId) {
toggleButton.setContentDescription(toggleButton.getContext().getText(resId));
}
}
The EndDrawerToggle class works exactly the same way as ActionBarDrawerToggle does when used with a Toolbar (except the constructor call doesn't need an Activity argument): first instantiate the toggle, then add it as a DrawerListener, and sync it in the Activity's onPostCreate() method. If you're already overriding the Activity's onConfigurationChanged() method, you'll want to call the toggle's corresponding method there, like you would for an ActionBarDrawerToggle.
private EndDrawerToggle drawerToggle;
public void initNavigationDrawer() {
...
drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
drawerToggle = new EndDrawerToggle(drawerLayout,
toolbar,
R.string.drawer_open,
R.string.drawer_close);
drawerLayout.addDrawerListener(drawerToggle);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
If you have two drawers and need to use ActionBarDrawerToggle and EndDrawerToggle simultaneously, it is possible, but we'll need to handle intercepting and dispatching drawer motion events to the correct toggle.
If you prefer fewer classes, you could subclass ActionBarDrawerToggle and merge EndDrawerToggle's functionality into it, dispatching each DrawerListener method call either to the super class, or to the local end toggle code.
However, composition is arguably much cleaner here, and it will let us use EndDrawerToggle as is. This example is a DrawerListener that relays syncState() and onConfigurationChanged() calls to each toggle, but dispatches the listener method calls only to the appropriate one, depending on which drawer is moving.
public class DualDrawerToggle implements DrawerLayout.DrawerListener {
private final DrawerLayout drawerLayout;
private final Toolbar toolbar;
private final ActionBarDrawerToggle actionBarDrawerToggle;
private final EndDrawerToggle endDrawerToggle;
public DualDrawerToggle(Activity activity, DrawerLayout drawerLayout, Toolbar toolbar,
int startDrawerOpenContDescRes, int startDrawerCloseContDescRes,
int endDrawerOpenContDescRes, int endDrawerCloseContDescRes) {
this.drawerLayout = drawerLayout;
this.toolbar = toolbar;
this.actionBarDrawerToggle =
new ActionBarDrawerToggle(activity, drawerLayout, toolbar,
startDrawerOpenContDescRes, startDrawerCloseContDescRes);
this.endDrawerToggle =
new EndDrawerToggle(drawerLayout, toolbar,
endDrawerOpenContDescRes, endDrawerCloseContDescRes);
}
public void syncState() {
actionBarDrawerToggle.syncState();
endDrawerToggle.syncState();
}
public void onConfigurationChanged(Configuration newConfig) {
actionBarDrawerToggle.onConfigurationChanged(newConfig);
// Fixes bug in ABDT, which only reloads the up nav indicator, for some reason.
final DrawerArrowDrawable dad = new DrawerArrowDrawable(toolbar.getContext());
actionBarDrawerToggle.setDrawerArrowDrawable(dad);
endDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onDrawerSlide(#NonNull View drawerView, float slideOffset) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerSlide(drawerView, slideOffset);
} else {
endDrawerToggle.onDrawerSlide(drawerView, slideOffset);
}
}
#Override
public void onDrawerOpened(#NonNull View drawerView) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerOpened(drawerView);
} else {
endDrawerToggle.onDrawerOpened(drawerView);
}
}
#Override
public void onDrawerClosed(#NonNull View drawerView) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerClosed(drawerView);
} else {
endDrawerToggle.onDrawerClosed(drawerView);
}
}
#Override
public void onDrawerStateChanged(int newState) {}
#SuppressLint("RtlHardcoded")
static boolean isStartDrawerView(View drawerView, int layoutDirection) {
final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
final int horizontalGravity = gravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK;
if ((horizontalGravity & GravityCompat.RELATIVE_LAYOUT_DIRECTION) > 0) {
return horizontalGravity == GravityCompat.START;
} else {
if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
return horizontalGravity == Gravity.RIGHT;
} else {
return horizontalGravity == Gravity.LEFT;
}
}
}
}
Again, DualDrawerToggle works exactly the same way as ActionBarDrawerToggle does when used with a Toolbar, except for the extra content description resource IDs in the constructor.
Do note that the one DualDrawerToggle creates and manages both other toggles internally. You don't need to set up any other toggle instances in your Activity; just the DualDrawerToggle.
Notes:
If you read through the code, you'll see that EndDrawerToggle – and therefore also DualDrawerToggle – can be readily adapted to put a toggle on pretty much anything that can display a Drawable and register clicks; e.g., a FloatingActionButton, an options menu item, a TextView's compound drawable, etc. Simply replace the AppCompatImageButton with your target UI component, which can be passed in the constructor in place of the Toolbar, since the toggle won't be added to that anymore.
Additionally, this could be modified to work with the start/left-aligned drawer, too – completely replacing ActionBarDrawerToggle – so that its toggle could be placed on those various components, as well.
The AppCompatImageButton used here is a regular child of the Toolbar. If you're using a menu on the Toolbar, that menu will take precedence in the layout, and push the toggle inward. To keep it on the outside, you can modify the class as described above to set the toggle on an action menu item. I've an example of that in my answer here.
That menu item example might also be useful if your design requires you use the decor-supplied ActionBar in lieu of your own Toolbar. Though ActionBarDrawerToggle can work with a decor-supplied ActionBar, this example can not, as is.

In your android manifest add this line:
android:supportsRtl="true"
to your application, like so:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
Then in your onCreate method, add this line:
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
WARNING::: This only works for SdkVersion 17+, so if your application targets a lower minimum SDK, you will have to create a custom menu and override the OnCreateOptions method(Unless there's another way which I'm not aware of, which is definitely possible).
https://developer.android.com/guide/topics/manifest/application-element.html#supportsrtl

Related

Android : Unable to integrate Drawer navigation because already calling extends for Google-Maps

I am working on an Android project in which I would like to add Drawer functionality, for which I already have classes and all ready.
THe problem is the Drawer code works by extends or extending the class which wants to add a drawer, and similarly my GoogleMaps code works in the same way. But because of Multiple-inheritance, I cannot extend 2 classes.
What should I do?
Google-maps code :
public class MapsActivity extends FragmentActivity {
GoogleMap googleMap;
SharedPreferences sharedPreferences;
int locationCount = 0;
private RestaurantServiceImpl restaurantService = new RestaurantServiceImpl();
List<RestRestaurant> restRestaurantList = new ArrayList<>();
GPSTracker gps;
double longitude, latitude;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mapsact);
SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
// Getting GoogleMap object from the fragment
googleMap = fm.getMap();
// Enabling MyLocation Layer of Google Map
googleMap.setMyLocationEnabled(true);
// Opening the sharedPreferences object
sharedPreferences = getSharedPreferences("location", 0);
// Getting number of locations already stored
locationCount = sharedPreferences.getInt("locationCount", 0);
// Getting stored zoom level if exists else return 0
String zoom = sharedPreferences.getString("zoom", "12");
gps = new GPSTracker(MapsActivity.this);
if (gps.canGetLocation()) {
longitude = gps.getLongitude();
latitude = gps.getLatitude();
restRestaurantList = this.restaurantService.getRestaurantsByLocation(longitude,latitude);
double lat=0, longi=0;
for(RestRestaurant restRestaurant : restRestaurantList){
drawMarker(new LatLng(restRestaurant.getLatitude(),restRestaurant.getLongitude()), restRestaurant.getRestaurantName(), restRestaurant.getRestaurantId());
lat = restRestaurant.getLatitude();
longi = restRestaurant.getLongitude();
}
googleMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(lat,longi)));
// Setting the zoom level in the map on last position is clicked
googleMap.animateCamera(CameraUpdateFactory.zoomTo(Float.parseFloat(zoom)));
} else {
gps.showSettingsAlert();
}
googleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
int restoId = Integer.valueOf(marker.getSnippet());
Intent intent = new Intent(MapsActivity.this, MenuCardList.class);
intent.putExtra("restaurantid", restoId);
startActivity(intent);
finish();
return true;
}
});
}
This class I need to extend to add a drawer :
public class DrawerLoader extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
// nav drawer title
private CharSequence mDrawerTitle;
// used to store app title
private CharSequence mTitle;
private ArrayList<DrawerModel> navDrawerItems;
private DrawerListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawerlayout);
}
public void set(String[] navMenuTitles, TypedArray navMenuIcons) {
mTitle = mDrawerTitle = getTitle();
navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);
navMenuIcons = getResources()
.obtainTypedArray(R.array.nav_drawer_icons);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.list_slidermenu);
navDrawerItems = new ArrayList<DrawerModel>();
If any more information is required, kindly let me know.
Ignoring all your work regarding a navigation drawer, this would be my preferred solution, since There is no need for a extra Fragment, List filling, new classes....
1, Create a nav_menu.xml (in menues folder):
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:checkableBehavior="single">
<item
android:id="#+id/drawer_home"
android:checked="true"
android:icon="#drawable/ic_home_black_24dp"
android:title="Home"/>
<item
android:id="#+id/drawer_favourite"
android:icon="#drawable/ic_favorite_black_24dp"
android:title="Favourites"/>
<item
android:id="#+id/drawer_settings"
android:icon="#drawable/ic_settings_black_24dp"
android:title="Settings"/>
</group>
2, Wrap your activites layout with a DrawerLayout:
<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">
<!-- Your activity layout here-->
<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_header"
app:menu="#menu/nav_menu"/>
</android.support.v4.widget.DrawerLayout>
3, Update your activities java code:
//If you have a toolbar (recommended!)
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
//and finally the Navigation View Code:
final NavigationView navigation = (NavigationView) findViewById(R.id.navigation);
navigation.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
navigation.setCheckedItem(menuItem.getItemId());
drawerLayout.closeDrawers();
switch (menuItem.getItemId()) {
case R.id.drawer_home:
//open fragment home
return true;
case R.id.drawer_favourite:
//open fragment favourite
return true;
case R.id.nav_drawer_channels:
showFragment(2);
return true;
case R.id.drawer_settings:
//open settings
return true;
}
return false;
}
});
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(
this,
drawerLayout,
toolbar,
R.string.drawer_open, //simply a String "open"
R.string.drawer_close) { //simply a String "close"
public void onDrawerClosed(View view) {
super.onDrawerOpened(drawerLayout);
drawerToggle.syncState();
}
public void onDrawerOpened(View drawerView) {
super.onDrawerClosed(drawerLayout);
drawerToggle.syncState();
}
};
drawerLayout.setDrawerListener(drawerToggle);
drawerToggle.syncState();
//And, last but not least, open the drawer with a Click on 'home'
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
And you are done! No messing with extra fragment, unnecessary and messy code.

Including appcompact v7 toolbar error

I had made a common layout to include V7 toolbar in every activity , and its common class file CommonToolbar.java to handle its properties.
layout_common_toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_common"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/abc_action_bar_default_height_material"
android:background="?attr/colorPrimaryDark"/>
CommonToolbar.java
public class CommonToolbar {
Activity activity;
Toolbar toolbar;
CommonToolbar(Activity activity, View view, String title) {
super();
this.activity = activity;
toolbar = (Toolbar)view.findViewById(R.id.toolbar_common);
toolbar.setTitle(title);
toolbar.setTitleTextColor(activity.getResources().getColor(R.color.white));
}
void setNav() {
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
activity.onBackPressed();
}
});
}
void setMenuListner() {
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
/* case R.id.searchItem:
Toast.makeText(getApplicationContext(), "Search", Toast.LENGTH_SHORT).show();
break;
case R.id.filterItem:
Toast.makeText(getApplicationContext(), "Filter", Toast.LENGTH_SHORT).show();
break;*/
}
return true;
}
});
toolbar.inflateMenu(R.menu.common_toolbar_menu);
}
}
Using it like:
In Layout
<include android:layout_height="#dimen/abc_action_bar_default_height_material"
android:id="#+id/includeSurgicalDetail"
android:layout_width="match_parent"
layout="#layout/layout_common_actionbar"/>
In Activity
View includedLayout = findViewById(R.id.includeSurgicalDetail);
CommonToolbar commonToolbar = new CommonToolbar(SurgicalDetail.this, includedLayout, pName);
commonToolbar.setMenuListner();
commonToolbar.setNav();
But I get the following error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.greyline.eswasthyaprojectv3/com.eswasthyaV3.SurgicalDetail}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.Toolbar.setTitle(java.lang.CharSequence)' on a null object reference
If you do not want to write the same option menu code, you should extend the Activity instead.
Write a BaseActivity class like:
public class BaseActivity extends Activity{
protected Toolbar toolbar;
public void onCreate(Bundle savedInstaceState){
super.onCreate(savedInstanceState);
//initialize the Toolbar, set the menu listener, nav, etc
toolbar = (Toolbar)findViewById(R.id.toolbar_common);
}
}
Then for all the Activity that you want to have the share code, extends BaseActivity instead of the Activity. So you do not need to write the same option menu code over and over.

ActionBarSherlock menu ForceOverflow not showing

My problem is that when you open the app is not shown the overflow menu in the actionbar.
If you see en the MainActivity class I have a onOptionsItemSelected for the navigationdrawer, so when I create on the bottom a onCreatedOptionMenu with their respective onOptionsItemSelected fails.
and I dont know how to fix it.
This is what I want
Image
But nothing appears in the actionbar when I open application
This is my menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
style="#style/Theme.Sherlock">
<item
android:id="#+id/more"
android:icon="#drawable/ic_action_overflow"
android:title="#string/more"
android:showAsAction="always"/>
<menu >
<item
android:id="#+id/contacto"
android:title="#string/contacto"
android:showAsAction="always|withText"/>
<item
android:id="#+id/recomenda"
android:title="#string/recomenda"
android:showAsAction="always|withText"/>
<item
android:id="#+id/salir"
android:title="#string/salir"
android:showAsAction="always|withText"/>
</menu>
MainActivity.java:
public class MainActivity extends SherlockFragmentActivity {
// Declare Variables
DrawerLayout mDrawerLayout;
ListView mDrawerList;
ActionBarDrawerToggle mDrawerToggle;
MenuListAdapter mMenuAdapter;
String[] title;
Fragment fragment0 = new Fragment0();
//20 more
private CharSequence mDrawerTitle;
private CharSequence mTitle;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the view from drawer_main.xml
setContentView(R.layout.drawer_main);
// Get the Title
mTitle = mDrawerTitle = "¿Qué buscás?";
// Generate title
title = new String[] { " ASD ", "CORTE LÁSER", "CORTE METALES",
"CORTE POR CHORRO DE AGUA", "CURSOS", "EQUIPOS DE VIDEO", "FICHAS TÉCNICAS",
"FOTÓGRAFOS", "GRÁFICAS", "IMPRESIÓN 3D", "LIBRERÍAS Y PAPELERAS", "MAQUETAS Y PROTOTIPOS",
"MODELADO 3D", "MODELOS", "PLÁSTICOS", "ROUTER", "SUBLIMACIÓN", "TELGOPOR", "TERMOFORMADO",
"TORNERO MADERA", "TORNERO METALES", "VINILOS" };
// Locate DrawerLayout in drawer_main.xml
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
// Locate ListView in drawer_main.xml
mDrawerList = (ListView) findViewById(R.id.listview_drawer);
// Set a custom shadow that overlays the main content when the drawer
// opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
// Pass string arrays to MenuListAdapter
mMenuAdapter = new MenuListAdapter(MainActivity.this, title);
// Set the MenuListAdapter to the ListView
mDrawerList.setAdapter(mMenuAdapter);
// Capture listview menu item click
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// Enable ActionBar app icon to behave as action to toggle nav drawer
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open,
R.string.drawer_close) {
public void onDrawerClosed(View view) {
// TODO Auto-generated method stub
super.onDrawerClosed(view);
}
public void onDrawerOpened(View drawerView) {
// TODO Auto-generated method stub
// Set the title on the action when drawer open
getSupportActionBar().setTitle(mDrawerTitle);
super.onDrawerOpened(drawerView);
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
selectItem(0);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
if (mDrawerLayout.isDrawerOpen(mDrawerList)) {
mDrawerLayout.closeDrawer(mDrawerList);
} else {
mDrawerLayout.openDrawer(mDrawerList);
}
}
return super.onOptionsItemSelected(item);
}
// ListView click listener in the navigation drawer
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
selectItem(position);
}
}
private void selectItem(int position) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Locate Position
switch (position) {
case 0:
ft.replace(R.id.content_frame, fragment0);
ft.addToBackStack(null);
break;
case 1:
ft.replace(R.id.content_frame, fragment1);
ft.addToBackStack(null);
break;
// and 19 more cases
}
ft.commit();
mDrawerList.setItemChecked(position, true);
// Get the title followed by the position
setTitle(title[position]);
// Close drawer
mDrawerLayout.closeDrawer(mDrawerList);
}
public boolean onCreatedOptionMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.menu1, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggles
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
}
And the Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
//...
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.Sherlock.Light.ForceOverflow" >
<meta-data
//...
</application>
Please if you need some more information to answer, ask me
(I have not yet allowed to post images to show you my app)
Sorry if I made a mistake when posting, also for my English, I notice that I am beginner coding.
EDIT:
I think that solves the fact that the menu does not appear on the actionbar with this code and deleting the menu.xml:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
SubMenu subMenu = menu.addSubMenu("Más");
subMenu.add("Volver");
subMenu.add("Contacto");
subMenu.add("Salir");
subMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return true;
}
And added this in the onOptionsItemSelected already have in the MainActivity.java:
if (item.getTitle().toString().equalsIgnoreCase("Publicá!")) {
Intent in = new Intent(getApplicationContext(),Publica.class);
startActivity(in);
Toast.makeText(this, "Publicá tu Negocio/Local/Emprendimiento", Toast.LENGTH_LONG).show();
} if (item.getTitle().toString().equalsIgnoreCase("Contacto")) {
Intent in = new Intent(getApplicationContext(),Contacto.class);
startActivity(in);
Toast.makeText(this, "Contactate y reportanos ...", Toast.LENGTH_LONG).show();
}
if (item.getTitle().toString().equalsIgnoreCase("Salir")) {
Intent i = new Intent(); i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_HOME); i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i); android.os.Process.killProcess(android.os.Process.myPid());
Toast.makeText(this, "<-- Busca lo que necesitas", Toast.LENGTH_LONG).show();
}
Now i Have something like This
But not know to generate the menu on the actionbar be an icon instead of text like "Type".
That is my problem now.
This is what you need to do with the item tags
android:showAsAction=["ifRoom" | "never" | "withText" | "always" | "collapseActionView"]
always will always show you menus, never will let your menu item to come in the overflow mode..
set
android:showAsAction="never"
look here for more description.

Using one navigation drawer that shows different options depending on the activity that is currently showing

I am trying to implement a navigation drawer in a BaseActivity, that shows different options depending on the activity that is currently showing. For that, I developed a BaseActivity, that implements the navigation drawer, and decides what to show, depending on the activity that is currently showing. The purpose of this, is to make all other activities that need to use the navigation drawer, expand the BaseActivity.
The following code, shows no errors, but the navigation drawer shows itself completely empty, and does not show when I click the 'home' button, neither the 'menu' button, a functionality that I implemented with the 'onKeyDown' method. It just shows, when I use the following gesture: move the finger from the left to the right in the left side of the screen.
When I do the same in each class I need, instead of using a BaseActivity, everything works perfeclty fine.
I have been trying this for days now and I still do not understand why, the content of the navigation drawer is still not showing. I would appreciate some help please. Thanks in advance.
Here, the core classes of the problem:
BaseActivity.java
public abstract class BaseActivity extends ActionBarActivity
{
public DrawerLayout drawerLayout = null;
public ActionBarDrawerToggle drawerToggle = null;
public Activity currentActivity = null;
public ArrayList<Item> navDrawerItems = new ArrayList<Item>();
public ItemListAdapter adapter = null;
public ListView drawerList = null;
int id = 0;
protected void onCreate(Bundle savedInstanceState, int resLayoutID)
{
super.onCreate(savedInstanceState);
setContentView(resLayoutID);
currentActivity = this;
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = new ActionBarDrawerToggle(currentActivity,
drawerLayout,
R.drawable.ic_drawer,
R.string.open_menu,
R.string.close_menu)
{
public void onDrawerClosed(View view)
{
Log.e("", "Close drawer");
getSupportActionBar().setTitle(getTitle());
ActivityCompat.invalidateOptionsMenu(currentActivity);
}
public void onDrawerOpened(View drawerView)
{
Log.e("", "Open drawer");
getSupportActionBar().setTitle(getTitle());
ActivityCompat.invalidateOptionsMenu(currentActivity);
}
};
drawerLayout.setDrawerListener(drawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// Populate navigation drawer depending on the activity
// that is currently showing.
if (this.getClass().getSimpleName().equals("Z"))
setUpNavigationForZActivity();
}
private void setUpNavigationForZActivity()
{
Log.e("", "In setUpNavigationForZActivity");
// Prepare list items.
id = R.string.title_activity_A;
navDrawerItems.add(new NavigationDrawerItem(getString(id), Utils.activityIcon().get(id)));
id = R.string.title_activity_B;
navDrawerItems.add(new NavigationDrawerItem(getString(id), Utils.activityIcon().get(id)));
// Populate view.
drawerList = (ListView) findViewById(R.id.left_menu);
adapter = new ItemListAdapter(currentActivity, navDrawerItems;
drawerList.setAdapter(adapter);
drawerList.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{
Intent intent = null;
switch(position)
{
case 0:
intent = new Intent(currentActivity, A.class);
startActivity(intent)
break;
case 1:
intent = new Intent(currentActivity, B.class);
startActivity(intent)
break;
default:
}
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (drawerToggle.onOptionsItemSelected(item))
return true;
return super.onOptionsItemSelected(item);
}
#Override
protected void onPostCreate(Bundle savedInstanceState)
{
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent e)
{
Log.e("", "onKeyDown");
if (keyCode == KeyEvent.KEYCODE_MENU)
{
if(!drawerLayout.isDrawerOpen(Gravity.LEFT))
drawerLayout.openDrawer(Gravity.LEFT);
else
drawerLayout.closeDrawer(Gravity.LEFT);
}
return super.onKeyDown(keyCode, e);
}
}
Z.java
public class Z extends BaseActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState, R.layout.Z);
setContentView(R.layout.Z);
//Other things to do...
}
}
Z.xml
<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" >
<!-- Main content view -->
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true" >
// Other layout and views configurations...
</ScrollView>
<!-- Navigation drawer -->
<ListView
android:id="#+id/left_menu"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/gray_7_5"
android:choiceMode="singleChoice" />
</android.support.v4.widget.DrawerLayout>
I do not exactly know why you would want to implement it that way but if you still want to do it this way i would suggest making your navdrawer use a listview with an adapter to draw items from an array and then have your base activity have a getData() call that you can override in your derived activities that will supply the data that the Adapter so that the listview will then draw the appropriate items in the navdrawer. You will then have to implement the onItemClick event for each listview per activity.

Open Android Navigation Drawer from an activity class

I am working on android Navigation Drawer and through their documentation it looks like, the drawer can only extend Fragment Activity, so that to open drawer from all my activities, I need to make all my activities a fragment, which is not a feasible solution.
Is there a way I can open a drawer that extends FragmentActivity from an Activity?
When I try to extend my drawer activity from Activity class, and another activity that will open the drawer extending the draweractivity class (here SlideMenuActivity), the app crashes giving NullPointerException.
Below is the code for opening a drawer layout but once the first activity launches, I am unable to access the drawer.
App is crashing on syncState point in onPostCreate method
#Override
protected void onPostCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onPostCreate(savedInstanceState);
getActionDrawerToggle().syncState();
}
public class SlideMenuActivity extends FragmentActivity implements OnItemClickListener
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setDrawerLayout();
setDrawerList();
if (savedInstanceState == null)
{
getDrawerListView().setSelectionAfterHeaderView();
getDrawerListView().setSelection(1);
selectItem(1);
}
}
//
// #Override
// public void setContentView(int layoutResID) {
// // TODO Auto-generated method stub
// super.setContentView(layoutResID);
// }
private DrawerLayout getDrawerView()
{
return (DrawerLayout)findViewById(R.id.drawer_layout);
}
private ListView getDrawerListView()
{
return (ListView) findViewById(R.id.left_drawer);
}
private ActionBarDrawerToggle getActionDrawerToggle()
{
ActionBarDrawerToggle drawerToggle=new ActionBarDrawerToggle(
this, /* host Activity */
getDrawerView(), /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
) {
#Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
#Override
public void onDrawerOpened(View view) {
super.onDrawerOpened(view);
}
};
return drawerToggle;
}
private void setDrawerLayout(){
// set a custom shadow that overlays the main content when the drawer opens
getDrawerView().setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK);
// enable ActionBar app icon to behave as action to toggle navigation drawer
getDrawerView().setDrawerListener(getActionDrawerToggle());
}
/**
* Set up the drawer's list view with items and click listener
*/
private void setDrawerList()
{
ImageView imageView=new ImageView(this);
imageView.setImageDrawable(getResources().getDrawable(R.drawable.precision_logo));
CustomBaseAdapter adapter=new CustomBaseAdapter();
adapter.list=getListViewData();
adapter.context=this;
ListView drawerList=getDrawerListView();
drawerList.setHeaderDividersEnabled(true);
drawerList.addHeaderView(imageView, null, false);
drawerList.setScrollingCacheEnabled(false);
drawerList.setAdapter(adapter);
drawerList.setOnItemClickListener(this);
}
private void selectItem(int position){
// update the main content by replacing fragments
// Fragment fragment=null;
// FragmentManager manager=getSupportFragmentManager();
switch (position) {
case 1:
this.startActivity(new Intent(this,SavedTankListActivity.class));
// fragment = new SavedMixesFragment();
// fragment = new SavedTankListActivity();
// manager.beginTransaction().replace(R.id.content_frame, fragment).commit();
break;
case 2:
// fragment=new MixGuideFragment();
// manager.beginTransaction().replace(R.id.content_frame, fragment).commit();
break;
default:
// fragment = new SavedMixesFragment();
// manager.beginTransaction().replace(R.id.content_frame, fragment).commit();
break;
}
getDrawerView().closeDrawer(getDrawerListView());
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onPostCreate(savedInstanceState);
getActionDrawerToggle().syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
getActionDrawerToggle().onConfigurationChanged(newConfig);
}
private ArrayList<DrawerListModel> getListViewData()
{
ArrayList<DrawerListModel> listViewData=new ArrayList<DrawerListModel>();
String[] listItemArray=getResources().getStringArray(R.array.slide_bar_list_item_array);
for(int index=0;index<listItemArray.length;index++)
{
DrawerListModel model=new DrawerListModel();
model.listItem=listItemArray[index];
listViewData.add(model);
}
return listViewData;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id)
{
view.setSelected(true);
selectItem(position);
}
public void openDrawerList(View view){
getDrawerView().openDrawer(getDrawerListView());
}
}
I too was looking through the documentation and thought that I had to switch all my activities into fragments. Just to clear it up, this is simply not the case. You can have as many elements under the linear layout or whatever as needed.
For example if your base activity without the appdrawer is:
<RelativeLayout>
<TextView>
</TextView>
<Button>
<Button>
</RelativeLayout>
Simply do
<android.support.v4.widget.DrawerLayout>
<RelativeLayout>
<TextView>
</TextView>
<Button>
<Button>
</RelativeLayout>
<ListView>
</ListView>
</android.support.v4.widget.DrawerLayout>
Supposedly you can have a main activity where you put the navigation drawer and all sub activity classes get to use the drawer, but what i don't understand is how do you avoid repeating the layout containing the drawerfor all sub activities.
Navigation Drawers do NOT need to be in a fragment. You can create a class that will then be extended from all of your activities (as you were attempting to do).
public class SlideMenuActivity extends Activity{..}
your main activity would look like
public class MainActivity extends SlideMenuActivity{..}
The SlideMenuActivity can be implemented in the same way as described in creating a navigation activity.
All of your XML pages would include this:
<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"
android:background="#FFFFFF" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#CCCCCC"
android:dividerHeight="1dp" />
</android.support.v4.widget.DrawerLayout>
Without seeing your logcat output, I am not sure why you are receiving an error, but hopefully this can help you get through a bit more of the navigation drawer code.

Categories