I keep reading about fragment and fragment back handling but still couldn't find a best solution here.
I have navigation drawer.
Lets pretend I have 2 items in my navigation drawer list (item1,item2)
when I click on item1 it's open A Fragment. in A Fragment after clicking in button opens B Fragment. So when B fragment is opened and I choose item2 from navigation drawer opens C Fragment.
And now when I press back button it should finish activity not go to B Fragment.
So in one word when I choose item1,item2 opens A fragment or C fragment, after pressing back button should finish activity but when opens B fragment(which is under item1) it have to go back to A Fragment
Please help it is very difficult for me. Thanks
public class MainActivity extends DefaultActivity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggleWrapper mDrawerToggle;
private ListView mDrawerListView;
private TextView mTitle;
private Runnable mPendingRunnable;
private Handler mHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mDrawerListView = (ListView) findViewById(R.id.left_drawer);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mFragmentManager = getSupportFragmentManager();
mHandler = new Handler();
LayoutInflater inflator = (LayoutInflater) this .getSystemService(LAYOUT_INFLATER_SERVICE);
View v = inflator.inflate(R.layout.custom_view, null);
mTitle = (TextView)v.findViewById(R.id.title);
getSupportActionBar().setBackgroundDrawable(null);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayShowCustomEnabled(true);
getSupportActionBar().setDisplayUseLogoEnabled(false);
getSupportActionBar().setDisplayShowHomeEnabled(false);
getSupportActionBar().setIcon(R.drawable.button_indicator_menu);
getSupportActionBar().setCustomView(v);
v.findViewById(R.id.menu).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!mDrawerLayout.isDrawerOpen(GravityCompat.START)){
mDrawerLayout.openDrawer(GravityCompat.START);
}else {
mDrawerLayout.closeDrawers();
}
}
});
mDrawerToggle = new ActionBarDrawerToggleWrapper(this, mDrawerLayout, R.drawable.transparent_gic, R.string.drawer_open, R.string.drawer_close){
public void onDrawerClosed(View view) {
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
if (mPendingRunnable != null) {
mHandler.post(mPendingRunnable);
mPendingRunnable = null;
}
}
public void onDrawerOpened(View drawerView) {
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
mDrawerToggle.addPartnerToggle(new ContentDisplaceDrawerToggle(this, mDrawerLayout, R.id.content_frame));
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.setDrawerListener(mDrawerToggle);
setLeftDrawerLeftMenu();
getFragment(getString(R.string.home));
setTitle(getString(R.string.home));
}
private void setLeftDrawerLeftMenu(){
final ArrayList<Item> items = new ArrayList<Item>();
items.add(new SectionItem(this,"icons_small_home",getString(R.string.home)));
items.add(new SectionItem(this,"icons_small_myacounts",getString(R.string.my_account)));
items.add(new EntryItem(getString(R.string.bonuses)));
items.add(new EntryItem(getString(R.string.account_recharge)));
items.add(new EntryItem(getString(R.string.tariff_plans)));
items.add(new EntryItem(getString(R.string.languages)));
EntryAdapter adapter = new EntryAdapter(MainActivity.this, items);
mDrawerListView.setAdapter(adapter);
mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
EntryItem item = (EntryItem) items.get(i);
setTitle(item.getTitle());
}
});
}
public void setTitle(final String title){
mTitle.setText(title);
mPendingRunnable = new Runnable() {
#Override
public void run() {
getFragment(title);
}
};
mDrawerLayout.closeDrawers();
}
public void getFragment(String name){
if(getString(R.string.orange_shops).equalsIgnoreCase(name)){
if (!(mSelectedFragment instanceof OrangeShopsFragment)){
addPage(new MyFragment(MainActivity.this),true);
}
}else if(getString(R.string.home).equals(name)){
addPage(new HomeFragment(MainActivity.this),false);
}else{
throw new RuntimeException("unknown fragment "+ name);
}
}
public void addPage(final DefaultFragment pDefaultFragment, final boolean isAddToBackStack){
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, pDefaultFragment);
if (isAddToBackStack) transaction.addToBackStack(null);
transaction.commitAllowingStateLoss();
}
}
It's not so difficult to clear the backstack.
Whenever the user clicks on any item on the drawer, just call
while(getSupportFragmentManager.popBackStackImmediate()){}
to clear what you had before.
edit:
I know it's a old question but I found a better/more efficient way of doing it using:
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
that was answered in the groups.google.com by one of the Android engineers, I replaced it on my app and the "clear stack" command works much faster now. Hope it helps.
I also faced this problem while working with fragments and navigation drawer. When we are navigating from one fragment to another fragment they all are added to same backstack. So that's why you are getting this problem. Inorder to overcome this problem i myself maintained back stack and handled the on backpressed method
If you post your code i will suggest a nice solution for your problem
Related
I currently have a Fragment hosted by an activity (which extends AppCompatActivity) layout. This parent activity sets a Navigation Drawer. The activity layout has a Toolbar which hosts a Spinner from the Fragment, which is created (inflated) via the Fragments onCreateOptionsMenu method.
In the onCreateOptionsMenu, I set an OnItemSelectedListener to the spinner which handles the selected value (which then updates the fragment). The problem I am facing though, is in the fragment (or perhaps the activity?): When I click the Navigation Drawer (toggle icon), this invokes the OnItemSelectedListener, which is not what I want. The code is working well handling the spinner in the menu, but I want to remove the OnItemSelectedListener response to the Navigation Drawer being clicked (it is currently creating a FragmentTransaction from the aforementioned OnItemSelectedListener method). The listener is even being triggered when I swipe in the Navigation Drawer and not even clicking the drawer toggle.
Activity:
public class MainActivity extends AppCompatActivity {
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> adapterView,
View view, int position, long l) {
// Code to run when the item gets clicked
selectItem(position);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
titles = getResources().getStringArray(R.array.titles);
drawerList = (ListView) findViewById(R.id.drawer);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
// Populate the list view
drawers = new Drawer["A", "B", "C"]
drawerList.setAdapter(new DrawerAdapter(this, R.layout.list_view_drawer, drawers));
drawerList.setOnItemClickListener(new DrawerItemClickListener());
// Display the correct fragment
if (savedInstanceState != null) {
currentPosition = savedInstanceState.getInt("position");
//setActionBarTitle(currentPosition);
} else {
selectItem(0);
}
// Create the ActionBarDrawerToggle
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
R.string.open_drawer, R.string.close_drawer) {
// Called when a drawer has settled in a completely closed stated
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
invalidateOptionsMenu();
}
// Called when a drawer has settled in a completely open state
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
invalidateOptionsMenu();
}
};
drawerLayout.setDrawerListener(drawerToggle);
}
}
Fragment:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.spinner_menu, menu);
MenuItem item = menu.findItem(R.id.spinner);
spinner = (Spinner) MenuItemCompat.getActionView(item);
ArrayAdapter<String> adapter = new ArrayAdapter<String
(getActivity(), R.layout.spinner, spinnerTitle);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id)
{
if (setNavigation) {
Toast.makeText(getContext(), "Item : " + position,
Toast.LENGTH_SHORT).show();
Fragment fragment;
if (position != 0) {
fragment = ExampleFragment.newInstance();
} else {
fragment = new ExampleFragment();
}
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment, "visible_fragment");
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
} else {
setNavigation = !setNavigation;
}
}// to close the onItemSelected
public void onNothingSelected(AdapterView<?> parent)
{
}
});
}
Inflate Menu XML:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/spinner"
android:title="ActionBar Spinner"
app:actionViewClass="android.widget.Spinner"
android:background="#ff00"
app:showAsAction="always" />
</menu>
The onDrawerOpened() and onDrawerClosed() overrides on the ActionBarDrawerToggle are calling invalidateOptionsMenu(), which is recreating the options menu, and firing your Spinner's OnItemSelectedListener each time the drawer opens or closes. It looks like you've got a boolean flag setup to ignore the listener firing immediately after the Spinner initialization, but after that menu has been created the first time, the flag has already been set, and each time the menu is recreated after that, your FragmentTransaction is running.
You can simply remove those calls, as the menu creation is handled sufficiently during the FragmentTransactions. You'd only really need to invalidate the menu if something in it needs to change after it's already been created. If that's all you were using the ActionBarDrawerToggle overrides for, you can just remove those altogether.
In the selectItem() method, adding .addToBackStack(null) to my transaction seems to break the toggle button (the one that brings out the nav drawer when tapped). It just disappears entirely when a fragment is loaded (by clicking on the corresponding item in the nav drawer). If I comment out that line, the toggle button remains and works perfectly fine.
I need to call addToBackStack because I want back button functionality to work for those fragments, though. Why is it causing this issue?
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
Log.d(TAG, "Item " + position + " selected");
selectItem(position);
}
}
/** Swaps fragments in the main content view */
private void selectItem(int position) {
// Create a new fragment and specify the planet to show based on position
Fragment aboutFragment = new AboutFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
Log.d(TAG, "selectItem() with position " + position);
switch(position) {
case 0:
fragmentManager.beginTransaction()
.replace(R.id.contributionsFragmentContainer, contributionsList)
//.addToBackStack(null)
.commit();
Log.d(TAG, "contributionsListFragment committed");
break;
case 1:
fragmentManager.beginTransaction()
.replace(R.id.contributionsFragmentContainer, aboutFragment)
//.addToBackStack(null)
.commit();
Log.d(TAG, "aboutFragment committed");
break;
}
// Highlight the selected item, update the title, and close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(itemArray[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
#Override
public void setTitle(CharSequence title) {
if (title != null && getActionBar() != null) {
getActionBar().setTitle(title);
}
}
private void addDrawerItems() {
itemArray = new String[] {"Home", "About", "Nearby", "Settings", "Feedback"};
Log.d(TAG, "Adding to itemArray");
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, itemArray);
mDrawerList.setAdapter(mAdapter);
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
}
private void setupDrawer() {
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(R.string.title_activity_contributions);
setContentView(R.layout.activity_contributions);
Log.d("ContributionsActivity", "onCreate()");
// Activity can call methods in the fragment by acquiring a reference to the Fragment from FragmentManager, using findFragmentById()
contributionsList = (ContributionsListFragment) getSupportFragmentManager().findFragmentById(R.id.contributionsListFragment);
//Set up navigation drawer
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//getSupportActionBar().setHomeButtonEnabled(true);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.drawer_list);
addDrawerItems();
setupDrawer();
...
}
I find a lot of tutorials on the Internet on how to implement a navigation drawer for Android Studio.
However, let's say I want to create a navigation drawer for any activity but with different items, is it possible to create some sort of baseactivity so I only need to write the NavDrawerItems and the DrawerItemClickListener ...
Can this BaseActivity be achieved or is it too far fetched? I searched alot on Google about this, but didn't find any tutorials concerning this particular question I got :( Most of the baseactivity tutorials I find are for navigation drawer with the same items.
Edit:
Code I have for now, but in my opinion it's a bit long to read:
Tutorials I used are:
https://trinitytuts.com/android-navigation-drawer-with-material-design-arrow/ http://thedeveloperworldisyours.com/android/put-image-navigation-drawer/
public class MainActivity extends Activity {
private Context context;
private RelativeLayout mDrawerRelativeLayout;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mRequestsArray;
Toolbar toolbar;
TextView toolbarTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.context = this;
mTitle = mDrawerTitle = getTitle();
mRequestsArray = new String[] { "Catalog", "Account", "Checkout", "Utilities"};
mDrawerRelativeLayout = (RelativeLayout) findViewById(R.id.left_drawer);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.list_view_drawer);
toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbarTitle = (TextView) findViewById(R.id.titletool);
// set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mRequestsArray));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
toolbar, /* 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 */
) {
public void onDrawerClosed(View view) {
toolbarTitle.setText(mTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
toolbarTitle.setText(mDrawerTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
setTitle(getTitle());
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
/* Called whenever we call invalidateOptionsMenu() */
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new CatalogFragment();
break;
case 1:
fragment = new AccountFragment();
break;
case 2:
fragment = new CheckoutFragment();
break;
case 3:
fragment = new UtilitiesFragment();
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_frame, fragment);
fragmentTransaction.commit();
}
selectItem(position);
mDrawerLayout.closeDrawer(mDrawerRelativeLayout);
}
}
private void selectItem(int position) {
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mRequestsArray[position]);
mDrawerLayout.closeDrawer(mDrawerRelativeLayout);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
toolbarTitle.setText(mTitle);
}
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
#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 toggls
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
In my opinion, it's possible. You can set it when preparing your list data, as the following sample
private static void prepareListData(final Context context) {
final Activity activity = ((Activity) context);
String activity_name = context.getClass().getSimpleName().replace("Activity", "");
sListDataHeader = new ArrayList<>();
sListDataChild = new HashMap<>();
// adding header data, except current activity
String[] mItemHeaders = activity.getResources().getStringArray(R.array.items_array_expandable_header);
// here...
for (String item : mItemHeaders) {
if (!item.toLowerCase().equals(activity_name.toLowerCase())) {
sListDataHeader.add(item);
}
}
String[] mItemMainChild = activity.getResources().getStringArray(R.array.items_array_expandable_main_child);
// Child data
List<String> listChild = Arrays.asList(mItemMainChild);
// Header, Child data
for (int i = 0; i < sListDataHeader.size() - 2; i++) {
sListDataChild.put(sListDataHeader.get(i), new ArrayList<String>());
}
sListDataChild.put(sListDataHeader.get(sListDataHeader.size() - 1), listChild);
}
Hope this help!
I'm currently using within my app the android.support.v7.widget.Toolbar and android.support.v4.widget.DrawerLayout. Everything is working right, but there is a slight thing I want to change its behaviour.
When I open the drawer, the whole drawer occupies the space of the Toolbar. It would be nice that the Toolbar stays on top, like in the Google Music app. How can I achieve that?
But the most important thing isn't the previous. At first, the icon which is loaded in the application is the three stripped one. I've realised that after opening the drawer, the icon changes to an arrow. And after loading a fragment, the arrow remains there as the Toolbar icon, even if I press back until the first screen. How could I avoid the arrow appearing from after opening the drawer? I'd want to change this icon manually, specially when I load lower level fragments.
Thanks for your help!
Code:
public class HomeActivity extends BaseActivity {
...
private DrawerLayout mDrawer;
private ActionBarDrawerToggle mDrawerToggle;
private ListView mDrawerList;
private ListView mDrawerRightList;
private RelativeLayout mDrawerRelativeLayout;
private String[] mDrawerMenuTitles;
private Toolbar mToolbar;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDrawerMenuTitles = getResources().getStringArray(R.array.main_menu_options);
mDrawer = (DrawerLayout) findViewById(R.id.drawer);
mDrawerRelativeLayout = (RelativeLayout) findViewById(R.id.theDrawerRelativeLayout);
mDrawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerRightList = (ListView) findViewById(R.id.theDrawerRight);
mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerRightList);
mDrawerList = (ListView) findViewById(R.id.theDrawer);
mDrawerList.setAdapter(new ArrayAdapter<String>(
getSupportActionBar().getThemedContext(),
R.layout.drawer_list_item,
mDrawerMenuTitles
));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
setmToolbar((Toolbar) findViewById(R.id.toolbar));
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawer,
mToolbar,
R.string.drawer_open,
R.string.drawer_close){
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// TODO Auto-generated method stub
super.onDrawerSlide(drawerView, slideOffset);
}
#Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
//getSupportActionBar().setTitle(CURRENT_FRAGMENT);
}
/** Called when a drawer has settled in a completely open state. */
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
//getSupportActionBar().setTitle("Configuración");
}
};
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerToggle.syncState();
mDrawer.setDrawerListener(mDrawerToggle);
setToolbarSubtitle(getString(R.string.misrutas_titulo));
initialisePreferences(savedInstanceState);
if (savedInstanceState == null) {
replaceFragment(DEFAULT_FRAGMENT);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
mDrawer.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
private class DrawerItemClickListener implements OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//selectItem(position);
final int thePos = position;
mDrawer.setDrawerListener( new DrawerLayout.SimpleDrawerListener(){
#Override
public void onDrawerClosed(View drawerView){
....
}
});
if(mDrawer.isDrawerOpen(GravityCompat.START))
mDrawer.closeDrawer(mDrawerRelativeLayout);
}
}
#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 toggls
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onBackPressed(){
setToolbarSubtitle(getString(R.string.app_name_subtitle));
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
finish();
}
else {
super.onBackPressed();
}
}
private void replaceFragment (String to){
if(!to.equalsIgnoreCase(CURRENT_FRAGMENT)){
CURRENT_FRAGMENT = to;
Fragment fragment = Fragment.instantiate(HomeActivity.this, to);
String backStateName = fragment.getClass().getName();
String fragmentTag = backStateName;
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped && manager.findFragmentByTag(fragmentTag) == null){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment, fragmentTag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
}
}
}
//More methods
....
}
EDIT:
I have been able to modify a little bit my layout, so that the Toolbar stays on top of the rest screen (drawer and fragment). But I haven't been able to control the icon. When I open the drawer, the hamburger icon converts into the arrow. When I close the drawer, the arrow is converted into the hamburger. But when I press an option within the drawer, a new fragment is inflated and the hamburger icon is replaced by the arrow until the application is closed, so that the hamburger icon is never seen.
How can I adapt the icon behaviour so that it doesn't change from hamburger to arrow when I click over a drawer option?
now I try to do a similiar navigation drawer as you...
Basically respect me is that I had a diferent package for navigation drawer that I think so is different from your navigation drawer... My package is:
//From android studio
compile 'com.android.support:appcompat-v7:21.0.0'
I don't know if this can help you, but I follow this greatest tutorial and my navigation drawer work it's similar as you wish!
http://androideity.com/2013/12/16/android-navigation-drawer-parte-1/
http://androideity.com/2014/02/26/android-navigation-drawer-parte-2/
I wait that I help you! Good luck!
PD: If you have a problems with this tutorial or same advice me! :D
At first glance seems that you are setting new drawer listener whenever item is selected, precisely in this snippet:
private class DrawerItemClickListener implements OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//selectItem(position);
final int thePos = position;
mDrawer.setDrawerListener( new DrawerLayout.SimpleDrawerListener(){
#Override
public void onDrawerClosed(View drawerView){
....
}
});
if(mDrawer.isDrawerOpen(GravityCompat.START))
mDrawer.closeDrawer(mDrawerRelativeLayout);
}
}
This snippet replaces ActionBarDrawerToggle (which implements DrawerListener as well), so no calls are made to ActionBarDrawerToggle which controls the icon.
How can I adapt the icon behaviour so that it doesn't change from hamburger to arrow when I click over a drawer option?
Relating to your previous statements, this sound vague to me. Why you'd be preventing this default behaviour? You can prevent morphing by not calling super calls in DrawerListener's methods.
I know that similar questions have been asked before, but I can't seem to find exactly what I’m looking for. My problem is that my back button is currently exiting the app. What I’m trying to do is to make it navigate to the previous fragment. Like if you open fragment1 - > fragment2 and then press the back button it would take you back to fragment1.
My current code looks like this.
public class MainActivity extends FragmentActivity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mPageTitles;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle();
mPageTitles = getResources().getStringArray(R.array.menu_array);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
// set a custom shadow that overlays the main content when the drawer
// opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPageTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
mDrawerLayout, /* 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 */
)
{
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
// Sets the firstpage if no state is found
if (savedInstanceState == null) {
selectItem(0);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
/* Called whenever we call invalidateOptionsMenu() */
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content
// view
return super.onPrepareOptionsMenu(menu);
}
// Toogles the drawer menu
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return mDrawerToggle.onOptionsItemSelected(item);
}
/* The click listner for ListView 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) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
switch (position) {
case 0:
KontaktInfoFragment kontakt = new KontaktInfoFragment();
fragmentTransaction.replace(R.id.content_frame, kontakt);
fragmentTransaction.addToBackStack("Replace");
fragmentTransaction.commit();
break;
case 1:
OmOssFragment omoss = new OmOssFragment();
fragmentTransaction.replace(R.id.content_frame, omoss);
fragmentTransaction.addToBackStack("Replace");
fragmentTransaction.commit();
break;
case 2:
MainScreenActivity mainscreen = new MainScreenActivity();
fragmentTransaction.replace(R.id.content_frame, mainscreen);
fragmentTransaction.addToBackStack("Replace");
fragmentTransaction.commit();
break;
case 3:
LoginFragment login = new LoginFragment();
fragmentTransaction.replace(R.id.content_frame, login);
fragmentTransaction.addToBackStack("Replace");
fragmentTransaction.commit();
break;
case 4:
ContactFormFragment form = new ContactFormFragment();
fragmentTransaction.replace(R.id.content_frame, form);
fragmentTransaction.addToBackStack("Replace");
fragmentTransaction.commit();
break;
}
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPageTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}
}
When you press back button inside your fragment onBackPressed() method of your activity will be called if you have declared that..So handling back button for fragments within navigation drawer can be one in this way..
MainActvity
public static boolean isMainActivityShown ;
public static boolean isFragment1Shown=false ;
public static boolean isFragment2Shown=false ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isMainActivityShown=true //inside onCreate method put isMainActivityShown true
.
.
.
}
Fragment currentFragment = new Fragment1();
isMainActivityShown=false; //when moving to fragment1
isFragment1Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
#Override
public void onBackPressed() {
if(isMainActivityShown)
{
finish();
}
else if(isFragment1Shown)
{
//write the code to handle back button when you are in Fragment1
}
else if(isFragment2Shown)
{ //When you are in Fragment 2 pressing back button will move to fragment1
Fragment currentFragment = new Fragment1();
isFragment2Shown=false;
isFragment1Shown=true;
FragmentManager frgManager;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
}
}
Fragment1
Fragment currentFragment = new Fragment2();
MainActivity.isFragment1Shown=false;
MainActivity.isFragment2Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();