Setup an imageview to open sidebar/menu android - android

Instead of using actionbar and setting up an icon, I could not use actionbar here. What I really want to do is to setup an imageview, which responds to user's click. When it is clicked, sidebar/menu will open or close, just like clicking on physical button at the button of android phone.
Is there any easy way to do so? (all the items in the sidebar are already done and work fine. I checked it by clicking on physical menu button on my phone)

Felt worthwhile to put the code for this example up on GitHub, as it was getting quite long:
Just set an OnClickListener to your ImageView, in the same way you would a Button.
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(this);
//...
#Override
public void onClick(View v) {
if(!mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
mDrawerLayout.openDrawer(GravityCompat.START);
} else {
mDrawerLayout.closeDrawer(GravityCompat.START);
}
}
You may want to add android:clickable = "true" to the xml for your ImageView, and android:background="?android:attr/selectableItemBackground" to gain feedback when the item is clicked.
This assumes you've set up your DrawerLayout somewhat like the following:
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout = null;
private ActionBarDrawerToggle mActionBarDrawerToggle = null;
private RecyclerView mRecyclerView = null;
private NavMenuAdapter adapter = null;
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mActionBarDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 0, 0);
mDrawerLayout.setDrawerListener(mActionBarDrawerToggle);
mRecyclerView = (RecyclerView) findViewById(R.id.navigation_menu_recycler);
adapter = new NavMenuAdapter();
mRecyclerView.setAdapter(adapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
mDrawerLayout.openDrawer(GravityCompat.START);
} else {
mDrawerLayout.closeDrawer(GravityCompat.START);
}
}
});
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mActionBarDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mActionBarDrawerToggle.onConfigurationChanged(newConfig);
}
Edit:
If you would like more control, you can define various states for your ImageView with a state list drawable, and use it in android:background instead of the above suggestion. Create a new xml file in your drawable folder (i.e. custom_selector.xml) with the following template:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/image_pressed"
android:state_pressed="true" />
<item android:drawable="#drawable/image_focused"
android:state_focused="true" />
<item android:drawable="#drawable/image_normal" />
</selector>
And define relevant images for pressed, focused/hover and normal states. Apply it with:
android:background="#drawable/custom_selector"

Building on PPartisan's answer, and assuming your Activity is MainActivity:
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(this);
//...
#Override
public void onClick(View v) {
MainActivity.this.openOptionsMenu();
}

Related

Android - setOnClickListern in nav_header_menu

I would add event in nav_header_menu.
I added login and register section then when user click I would show the relative layout page:
https://ibb.co/wwmFzSk
I added fragment_layout_user.xml and ActivityLoginUser class with code:
public class ActivityLoginUser extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_login_user);
ActionBar ab = getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);
}}
How can I implement this event in drawer menu?
You can follow below code to access the view of header.
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
View headerview = navigationView.getHeaderView(0);
TextView login= (TextView) headerview.findViewById(R.id.login);
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Your code here
}
});
I solved it also with #SumitSingh suggestion. I paste here the correct way to solve that.
We need to add this code in the activity class where we added navigation view.
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
View headerview = navigationView.getHeaderView(0);
TextView login= (TextView) headerview.findViewById(R.id.login);
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Your code here
}
});
Replace // Your code here with:
Intent loginUserIntent = new Intent(getContext(), ActivityLoginUser.class);
/* Start the new activity */
startActivity(loginUserIntent);
If you get error for getContext() please replace it with MainActivity.this
It works for me.

How to highlight the imagebutton when it is pressed

I want my imagebutton to hightlight it self, as the normal glow effect when a "normal" button is pressed. So i tried to put the image in, but then there is a "gray field" in the back of the image so i made it transparent so only the image will show but then the glow effect disappeared. Is there a solution to this? :)
please see imgur image as a example- Example image here
if it is to "hard" I can live with the gray field behind the image but is it possible then to make it green with the same highlight effect?
Should i put the code in MainActivity or my fragment java?
Fragment java
public class FirstFragment extends Fragment {
private View view ;
public FirstFragment(){
}
Button sendSMS;
Button sendSMSaon;
Button sendSMSaoff;
Button sendSMSrela1;
Button sendSMSrela2;
EditText msgTxt;
EditText aonTxt;
EditText aoffTxt;
EditText rela1txt;
EditText rela2txt;
Button taframnummer;
TextView nyanumtxt;
//TextView nya;
//TextView nsp;
TextView tstnr;
#SuppressWarnings("ResourceType")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.first_layout, container, false);
return inflater.inflate(R.layout.first_layout, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
view = getActivity().findViewById(R.id.content_frame);
nyanumtxt = (TextView) getActivity().findViewById(R.id.raderanumtxt);
sendSMS = (Button)view.findViewById(R.id.skicka);
sendSMSaon = (Button)view.findViewById(R.id.skickaaon);
sendSMSaoff = (Button)view.findViewById(R.id.skickaaoff);
sendSMSrela1 = (Button)view.findViewById(R.id.skickarela1);
sendSMSrela2 = (Button)view.findViewById(R.id.skickarela2);
msgTxt = (EditText)view.findViewById(R.id.Textmeddelande);
aonTxt = (EditText)view.findViewById(R.id.aon);
aoffTxt = (EditText)view.findViewById(R.id.aoff);
rela1txt = (EditText)view.findViewById(R.id.rela1txt);
rela2txt = (EditText)view.findViewById(R.id.relä2txt);
taframnummer = (Button) view.findViewById(R.id.taframnummer);
//nsp = (TextView) view.findViewById(R.id.nummertestsp);
// tstnr = (TextView) view.findViewById(R.id.numretladd);
// view = getActivity().findViewById(R.id.content_frame);
taframnummer.setVisibility(INVISIBLE);
msgTxt.setVisibility(INVISIBLE);
aonTxt.setVisibility(INVISIBLE);
aoffTxt.setVisibility(INVISIBLE);
rela1txt.setVisibility(INVISIBLE);
rela2txt.setVisibility(INVISIBLE);
sendSMSaoff.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String mymsgaoff = aoffTxt.getText().toString();
String theNumberr = nyanumtxt.getText().toString();
sendMsg(theNumberr, mymsgaoff);
}
}
);
sendSMSaon.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String mymsgaon = aonTxt.getText().toString();
String theNumberr = nyanumtxt.getText().toString();
sendMsg(theNumberr, mymsgaon);
}
}
);
sendSMS.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String myMsg = msgTxt.getText().toString();
String theNumberr = nyanumtxt.getText().toString();
sendMsg(theNumberr, myMsg);
}
}
);
sendSMSrela1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String myMsgrela1 = rela1txt.getText().toString();
String theNumberr = nyanumtxt.getText().toString();
sendMsg(theNumberr, myMsgrela1);
}
}
);
sendSMSrela2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String mymsgrela2 = rela2txt.getText().toString();
String theNumberr = nyanumtxt.getText().toString();
sendMsg(theNumberr, mymsgrela2);
}
}
);
// return view;
}
private void sendMsg(String theNumber, String myMsg)
{
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(theNumber, null, myMsg, null, null);
}
}
Here my MainActivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
//TextView tstnr;
TextView radertst;
Button sendSMSaon;
EditText aonTxt;
//TextView nrladd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) 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();
}
});
DrawerLayout 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();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
// tstnr = (TextView) findViewById(R.id.nummertestsp);
radertst = (TextView) findViewById(R.id.raderanumtxt);
sendSMSaon = (Button)findViewById(R.id.skickaaon);
aonTxt = (EditText)findViewById(R.id.aon);
// nrladd = (TextView)findViewById(R.id.numretladd);
}
//This is where the call for the value in the setttings are.
//Här är så att man kan lägga in values från inställningar till mainactivity.
public void displayData(View view){
SharedPreferences prefs =PreferenceManager.getDefaultSharedPreferences(this);
String name = prefs.getString("example_text", "");
radertst.setText(name + " ");
}
//downbelow is where the onresume so the value boots up with the app.
//nedanför är för att appen ska ladda koden i settings direkt när man startar
#Override
protected void onResume() {
super.onResume();
SharedPreferences prefs =PreferenceManager.getDefaultSharedPreferences(this);
String name = prefs.getString("example_text", "");
radertst.setText(name + " ");}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#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 onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
android.app.FragmentManager fragmentManager = getFragmentManager();
if (id == R.id.nav_first_layout) {
fragmentManager.beginTransaction()
.replace(R.id.content_frame
, new FirstFragment())
.commit();
// Handle the camera action
} else if (id == R.id.nav_second_layout) {
fragmentManager.beginTransaction()
.replace(R.id.content_frame
, new SecondFragment())
.commit();
} else if (id == R.id.nav_third_layout) {
fragmentManager.beginTransaction()
.replace(R.id.content_frame
, new ThirdFragment())
.commit();
}
else if (id == R.id.nav_share) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://hellmertz.se"));
startActivity(browserIntent);
return true;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
Put the imageView that you want to highlight above a View with bright color and set the visibility of the view equal to View.GONE. Now with your ImageButton
((ImageButton)findViewById(R.id.myImageBtn)).setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
myView.setVisibility(View.VISIBLE);
break;
}
case MotionEvent.ACTION_UP:
myView.setVisibility(View.GONE);
break;
// Your action here on button click
case MotionEvent.ACTION_CANCEL: {
myView.setVisibility(View.GONE);
break;
}
}
return true;
}
});
You can user selector drawable and have 3 different button drawables for each state. Create these file is drawables folder and add this line to button android:background="#drawable/button_selector"
button_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- pressed -->
<item android:drawable="#drawable/camera_button_hold" android:state_pressed="true"/>
<!-- focused -->
<item android:drawable="#drawable/camera_button_hold" android:state_focused="true"/>
<!-- default -->
<item android:drawable="#drawable/camera_button_normal"/>
</selector>
camera_button_hold.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:color="#673ab7"/>
</shape>
camera_button_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke
android:width="2dp"
android:color="#673ab7"/>
</shape>

Cannot catch toolbar home button click event

I've implemented the newest appcompat library and using the Toolbar as action bar. But the problem is I cannot catch the home button / hamburger icon click event. I've tried and looked everything but doesn't seem to find a similar problem.
This is my Activity class :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Set up the drawer.
navDrawerFragment =
(NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
navDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout),
toolbar);
}
And this is my NavigationDrawerFragment class :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
currentSelectedPosition = savedInstanceState.getInt(
STATE_SELECTED_POSITION);
fromSavedInstanceState = true;
}
// Select either the default item (0) or the last selected item.
selectItem(currentSelectedPosition);
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Indicate that this fragment would like
// to influence the set of actions in the action bar.
setHasOptionsMenu(true);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
drawerListView = (ListView) inflater.inflate(
R.layout.fragment_navigation_drawer, container, false);
drawerListView.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
selectItem(position);
}
});
//mDrawerListView.setAdapter();
//mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
return drawerListView;
}
public void setUp(int fragmentId, DrawerLayout drawerLayout, Toolbar toolbar) {
fragmentContainerView = getActivity().findViewById(fragmentId);
this.drawerLayout = drawerLayout;
// set a custom shadow that overlays the main
// content when the drawer opens
drawerLayout.setDrawerShadow(
R.drawable.drawer_shadow, GravityCompat.START);
// set up the drawer's list view
// with items and click listener
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the navigation drawer and the action bar app icon.
drawerToggle = new ActionBarDrawerToggle(
getActivity(),
drawerLayout,
toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
// If the user hasn't 'learned' about the drawer,
// open it to introduce them to the drawer,
// per the navigation drawer design guidelines.
if (!userLearnedDrawer && !fromSavedInstanceState) {
drawerLayout.openDrawer(fragmentContainerView);
}
// Defer code dependent on restoration of previous instance state.
drawerLayout.post(new Runnable() {
#Override
public void run() {
drawerToggle.syncState();
}
});
drawerLayout.setDrawerListener(drawerToggle);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, currentSelectedPosition);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Forward the new configuration the drawer toggle component.
drawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.d("cek", "item selected");
if (drawerToggle.onOptionsItemSelected(item)) {
Log.d("cek", "home selected");
return true;
}
return super.onOptionsItemSelected(item);
}
when I clicked a menu item, the log "item selected" gets called. But when I click on the home button, it opens navigation drawer but the log "home selected" never get called. I've set onOptionsItemSelected method inside my Activity as well, but it still doesn't get called.
If you want to know when home is clicked is an AppCompatActivity then you should try it like this:
First tell Android you want to use your Toolbar as your ActionBar:
setSupportActionBar(toolbar);
Then set Home to be displayed via setDisplayShowHomeEnabled like this:
getSupportActionBar().setDisplayShowHomeEnabled(true);
Finally listen for click events on android.R.id.home like usual:
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
if (menuItem.getItemId() == android.R.id.home) {
Timber.d("Home pressed");
}
return super.onOptionsItemSelected(menuItem);
}
If you want to know when the navigation button is clicked on a Toolbar in a class other than AppCompatActivity you can use these methods to set a navigation icon and listen for click events on it. The navigation icon will appear on the left side of your Toolbar where the the "home" button used to be.
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_nav_back));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("cek", "home selected");
}
});
If you want to know when the hamburger is clicked and when the drawer opens, you're already listening for these events via onDrawerOpened and onDrawerClosed so you'll want to see if those callbacks fit your requirements.
mActionBarDrawerToggle = mNavigationDrawerFragment.getActionBarDrawerToggle();
mActionBarDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// event when click home button
}
});
in mycase this code work perfect
This is how I do it to return to the right fragment otherwise if you have several fragments on the same level it would return to the first one if you don´t override the toolbar back button behavior.
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
I think the correct solution with support library 21 is the following
// action_bar is def resource of appcompat;
// if you have not provided your own toolbar I mean
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
if (toolbar != null) {
// change home icon if you wish
toolbar.setLogo(this.getResValues().homeIconDrawable());
toolbar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//catch here title and home icon click
}
});
}
I have handled back and Home button in Navigation Drawer like
public class HomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private ActionBarDrawerToggle drawerToggle;
private DrawerLayout drawerLayout;
NavigationView navigationView;
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
resetActionBar();
navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(this);
//showing first fragment on Start
getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).replace(R.id.content_fragment, new FirstFragment()).commit();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//listener for home
if(id==android.R.id.home)
{
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
onBackPressed();
else
drawerLayout.openDrawer(navigationView);
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START))
drawerLayout.closeDrawer(GravityCompat.START);
else
super.onBackPressed();
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Begin the transaction
Fragment fragment = null;
// Handle navigation view item clicks here.
int id = item.getItemId();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (id == R.id.nav_companies_list) {
fragment = new FirstFragment();
// Handle the action
}
// Begin the transaction
if(fragment!=null){
if(item.isChecked()){
if(getSupportFragmentManager().getBackStackEntryCount()==0){
drawer.closeDrawers();
}else{
removeAllFragments();
getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).replace(R.id.WikiCompany, fragment).commit();
drawer.closeDrawer(GravityCompat.START);
}
}else{
removeAllFragments();
getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).replace(R.id.WikiCompany, fragment).commit();
drawer.closeDrawer(GravityCompat.START);
}
}
return true;
}
public void removeAllFragments(){
getSupportFragmentManager().popBackStackImmediate(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
public void replaceFragment(final Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.WikiCompany, fragment).addToBackStack("")
.commit();
}
public void updateDrawerIcon() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
try {
Log.i("", "BackStackCount: " + getSupportFragmentManager().getBackStackEntryCount());
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
drawerToggle.setDrawerIndicatorEnabled(false);
else
drawerToggle.setDrawerIndicatorEnabled(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}, 50);
}
public void resetActionBar()
{
//display home
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
public void setActionBarTitle(String title) {
getSupportActionBar().setTitle(title);
}
}
and In each onViewCreated I call
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((HomeActivity)getActivity()).updateDrawerIcon();
((HomeActivity) getActivity()).setActionBarTitle("List");
}
This is how I implemented it pre-material design and it seems to still work now I've switched to the new Toolbar. In my case I want to log the user in if they attempt to open the side nav while logged out, (and catch the event so the side nav won't open). In your case you could not return true;.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!isLoggedIn() && item.getItemId() == android.R.id.home) {
login();
return true;
}
return mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
I changed the DrawerLayout a bit to get the events and be able to consume and event, such as if you want to use the actionToggle as back if you are in detail view:
public class ListenableDrawerLayout extends DrawerLayout {
private OnToggleButtonClickedListener mOnToggleButtonClickedListener;
private boolean mManualCall;
public ListenableDrawerLayout(Context context) {
super(context);
}
public ListenableDrawerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListenableDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Sets the listener for the toggle button
*
* #param mOnToggleButtonClickedListener
*/
public void setOnToggleButtonClickedListener(OnToggleButtonClickedListener mOnToggleButtonClickedListener) {
this.mOnToggleButtonClickedListener = mOnToggleButtonClickedListener;
}
/**
* Opens the navigation drawer manually from code<br>
* <b>NOTE: </b>Use this function instead of the normal openDrawer method
*
* #param drawerView
*/
public void openDrawerManual(View drawerView) {
mManualCall = true;
openDrawer(drawerView);
}
/**
* Closes the navigation drawer manually from code<br>
* <b>NOTE: </b>Use this function instead of the normal closeDrawer method
*
* #param drawerView
*/
public void closeDrawerManual(View drawerView) {
mManualCall = true;
closeDrawer(drawerView);
}
#Override
public void openDrawer(View drawerView) {
// Check for listener and for not manual open
if (!mManualCall && mOnToggleButtonClickedListener != null) {
// Notify the listener and behave on its reaction
if (mOnToggleButtonClickedListener.toggleOpenDrawer()) {
return;
}
}
// Manual call done
mManualCall = false;
// Let the drawer layout to its stuff
super.openDrawer(drawerView);
}
#Override
public void closeDrawer(View drawerView) {
// Check for listener and for not manual close
if (!mManualCall && mOnToggleButtonClickedListener != null) {
// Notify the listener and behave on its reaction
if (mOnToggleButtonClickedListener.toggleCloseDrawer()) {
return;
}
}
// Manual call done
mManualCall = false;
// Let the drawer layout to its stuff
super.closeDrawer(drawerView);
}
/**
* Interface for toggle button callbacks
*/
public static interface OnToggleButtonClickedListener {
/**
* The ActionBarDrawerToggle has been pressed in order to open the drawer
*
* #return true if we want to consume the event, false if we want the normal behaviour
*/
public boolean toggleOpenDrawer();
/**
* The ActionBarDrawerToggle has been pressed in order to close the drawer
*
* #return true if we want to consume the event, false if we want the normal behaviour
*/
public boolean toggleCloseDrawer();
}
}
The easiest approach we could do is change the home icon to a known icon and compare drawables (because android.R.id.home icon can differ to different api versions
so set a toolbar as actionbar
SetSupportActionBar(_toolbar);
_toolbar.NavigationIcon = your_known_drawable_here;
for (int i = 0; i < _toolbar.ChildCount; i++)
{
View v = _toolbar.GetChildAt(i);
if (v is ImageButton)
{
ImageButton imageButton = v as ImageButton;
if (imageButton.Drawable.GetConstantState().Equals(_bookMarkIcon.GetConstantState()))
{
//here v is the widget that contains the home icon you can add your click events here
}
}
}
In my case I had to put the icon using:
toolbar.setNavigationIcon(R.drawable.ic_my_home);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
And then listen to click events with default onOptionsItemSelected and android.R.id.home id
For anyone looking for a Xamarin implementation (since events are done differently in C#), I simply created this NavClickHandler class as follows:
public class NavClickHandler : Java.Lang.Object, View.IOnClickListener
{
private Activity mActivity;
public NavClickHandler(Activity activity)
{
this.mActivity = activity;
}
public void OnClick(View v)
{
DrawerLayout drawer = (DrawerLayout)mActivity.FindViewById(Resource.Id.drawer_layout);
if (drawer.IsDrawerOpen(GravityCompat.Start))
{
drawer.CloseDrawer(GravityCompat.Start);
}
else
{
drawer.OpenDrawer(GravityCompat.Start);
}
}
}
Then, assigned a custom hamburger menu button like this:
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetDefaultDisplayHomeAsUpEnabled(false);
this.drawerToggle.DrawerIndicatorEnabled = false;
this.drawerToggle.SetHomeAsUpIndicator(Resource.Drawable.MenuButton);
And finally, assigned the drawer menu toggler a ToolbarNavigationClickListener of the class type I created earlier:
this.drawerToggle.ToolbarNavigationClickListener = new NavClickHandler(this);
And then you've got a custom menu button, with click events handled.
Try this code
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home){
//You can get
}
return super.onOptionsItemSelected(item);
}
Add below code to your onCreate() metod
ActionBar ab = getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);
Apart from the answer provided by MrEngineer13, there is also another possible reason why the click event might not have been captured in the onOptionsSelected method. Your DrawerLayout may have overlayed your Toolbar's interface component in the layout XML file. Therefore, whenever you attempt to click the Home button, you're only clicking the DrawerLayout, but not the Home button that's located beneath it.
All you have to do now is rearrange your Toolbar in the corresponding layout XML file so that it is not blocked by any other UI component.
Programmatically, I did attempt to call the bringToFront() method on the toolbar (toolbar.bringToFront()). However, in my app's context, it does not seem to be the solution.

Why does my Java object reference an old activity after orientation change?

Background:
I have a FragmentActivity that uses a DrawerLayout. I created a class called NavDrawerManager to abstract out the code for dealing with the drawer layout. To construct this object, I need to pass in and keep a reference to an Activity. I use this activity reference to call findViewById(), and I also use the activity as a context when creating a list adapter, etc. I keep a reference to a NavDrawerManager object in my activity so I can perform callbacks and operations on the drawer layout.
UPDATE: Per Xaver's suggestion, I switched to extend FragmentActivity into a NavDrawerActivity. Instead of having a NavDrawerManager object in my activity, the superclass handles the nav drawer code. See updated code.
Issue:
Everything works fine until I change orientations. After changing orientations, it appears that my NavDrawerActivity still references the old layout. I say this because I have a progress bar and a couple of buttons in the DrawerLayout that I am attempting to update, but they don't reflect the updates.
When I call Activity.findViewById() to get the progress bar and make it visible, it doesn't show any changes, nor do any of the changes to the buttons show. Note: Activity.findViewById() does not return null. However, if I do the same things before changing orientation, the progress bar and buttons show the appropriate changes.
Code:
NavDrawerActivity:
public class NavDrawerActivity extends LowProfileFragmentActivity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private ExpandableListView mDrawerList;
private NavDrawerAdapter mListAdapter;
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
mDrawerToggle.onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
//Called via subclass after setContentView
protected void setupNavDrawer() {
initDrawerLayout();
initDrawerList();
setButton1();
setButton2();
}
private void initDrawerLayout() {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = getActionBarDrawerToggle();
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
private void initDrawerList() {
mDrawerList = (ExpandableListView) mDrawerLayout
.findViewById(android.R.id.list);
mListAdapter = getNavDrawerAdapter();
}
private ActionBarDrawerToggle getActionBarDrawerToggle() {
return new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_navigation_drawer, 0, 0) {
public void onDrawerClosed(View view) {
}
public void onDrawerOpened(View view) {
}
};
}
public void setDrawerLoading(boolean loading) {
ProgressBar progressBar = (ProgressBar) mDrawerLayout
.findViewById(R.id.progress_bar);
Button button1 = (Button) this.findViewById(R.id.button1);
Button button2 = (Button) this
.findViewById(R.id.button2);
/* None of the below changes appear after changing orientation */
if (loading) {
button1.setEnabled(false);
button2.setEnabled(false);
progressBar.setVisibility(View.VISIBLE);
} else {
progressBar.setVisibility(View.GONE);
button1.setEnabled(true);
button2.setEnabled(true);
}
}
private void setButton1() {
Button button1 = (Button) this.findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
});
}
private void setButton2() {
Button button2 = (Button) this
.findViewById(R.id.button2);
button2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
});
}
}
ExampleActivity:
public class ExampleActivity extends NavDrawerActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initUI();
}
private void initUI() {
setContentView(R.layout.activity_sift);
// Call the superclass method to set up the nav drawer
setupNavDrawer();
}
}
AndroidManifest.xml:
<activity
android:name="com.example.app.ExampleActivity"
android:label="#string/app_name"
android:launchMode="singleTop"
android:theme="#style/AppTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Wouldn't it be easier if you implemented a NavDrawerActivity instead of a NavDrawerManager? Generally things like this should be avoided. The UI should be handled solely by the Fragments or Activities themselves.
I understand why you would want to create such a NavDrawerManager, simply to make the whole thing reusable and a lot of abstraction is great, but when it is overdone it can become a problem. Don't focus so much on everything being perfectly abstracted and according to OOP standards. There is nothing wrong with an Activity having both a NavigationDrawer and hiding the notification bar. And if you already have an Activity that implements one of those two things you should extend it. Your only other option would be to reimplement the same behaviour in a second Activity and that would pretty much defeat the purpose of abstraction.
EDIT: I have refactored and improved your code, you really should not have so many different methods for everything, all the setup belongs in onCreate(), that you write extra methods for each step just introduces the possibility for additional errors. Try this:
public abstract class NavDrawerActivity extends LowProfileFragmentActivity {
private ActionBarDrawerToggle drawerToggle;
private DrawerLayout drawerLayout;
private ProgressBar progressBar;
private Button button1;
private Button button2;
private ExpandableListView drawerList;
private NavDrawerAdapter drawerListAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayout());
this.drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
this.drawerToggle = new ActionBarDrawerToggle(this, this.drawerLayout, R.drawable.icon_drawer, R.string.drawer_open, R.string.drawer_close);
this.drawerLayout.setDrawerListener(this.drawerToggle);
this.drawerList = (ExpandableListView) this.drawerLayout.findViewById(android.R.id.list);
this.progressBar = (ProgressBar) this.drawerLayout.findViewById(R.id.progress_bar);
this.button1 = (Button) findViewById(R.id.button1);
this.button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
});
this.button2 = (Button) findViewById(R.id.button2);
this.button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do something
}
});
this.drawerListAdapter = new NavDrawerAdapter(...);
this.drawerList.setAdapter(this.drawerListAdapter);
}
protected abstract int getLayout();
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
this.drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
this.drawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return this.drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
public void setDrawerLoading(boolean loading) {
this.button1.setEnabled(!loading);
this.button2.setEnabled(!loading);
this.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE);
}
}
As you can see I use an abstract method called getLayout() to pass the correct layout to setContentView(). getLayout() has to be implemented by all Activities which extend the NavDrawerActivity therfore giving the sub Activities control over the used layout.
As such your ExampleActivity should look like this:
public class ExampleActivity extends NavDrawerActivity {
#Override
protected int getLayout() {
return R.layout.activity_sift;
}
}
I tested everything and it's working for me.

Right Side navigation drawer icon always to the left [duplicate]

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

Categories

Resources