I have a simple navigation drawer. When I click on the item to change the current fragment it runs the code for the replace command runs but the fragment does not change.
Here is how I setup the navigation drawer:
private void setupNavigationMenu(final Bundle savedInstanceState) {
final DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.nav_drawer_items);
// Create the navigation drawer.
navigationDrawer = new NavigationDrawer(this, toolbar, drawerLayout, mDrawerList,
R.id.main_fragment_container);
String[] osArray = {"Discover Tunes", "My Discovered Tunes"};
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, osArray);
mDrawerList.setAdapter(mAdapter);
if (savedInstanceState == null) {
// Add the home fragment to be displayed initially.
discoverSongs();
}
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 0){
discoverSongs();
drawerLayout.closeDrawers();
} else {
myDiscoveredSongs();
drawerLayout.closeDrawers();
}
}
});
As you can see above I have onitemclicklistner running the functions discoverSongs() and myDiscoveredSongs(). When I click on the list I can see that the correct position is working and the correct function is running. But the fragment for discoverSongs() is always showing up.
Here is my discoverSongs() function:
public void discoverSongs() {
final Fragment fragment = new DiscoverSongFragment();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.main_fragment_container, fragment, DiscoverSongFragment.class.getSimpleName())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
setTitle("Discover Tunes");
And my myDiscoveredSongs() function looks like this:
public void myDiscoveredSongs() {
final Fragment fragment = new DiscoverSongFragment();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.main_fragment_container, fragment, MyDiscoveredSongsFragment.class.getSimpleName())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
setTitle("My Discovered Tunes");
}
Thanks for your help.
You are use same fragment name inmyDiscoveredSongs() method so change this line you code
final Fragment fragment = new DiscoverSongFragment();
in inmyDiscoveredSongs().
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 have two fragments FragmentHome and FragmentAbout, I have added NavigationDrawer to app when I click Home it opens FragmentHome and About opens FragmentAbout, when I open FragmentAbout I am also adding it to backstack. This is working fine.
Now the problem is when I click on About and press back button it goes to the FragmentHome but the NavigationDrawer still shows the About as selected item, I want to change this selected item to Home when I press back button from FragmentAbout
Home Activity:
public class ActivityHome extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
Toolbar toolbar;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Toolbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Drawer layout
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.nav_drawer_open, R.string.nav_drawer_close);
assert drawer != null;
drawer.setDrawerListener(toggle);
toggle.syncState();
// Navigation view
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
assert navigationView != null;
navigationView.setNavigationItemSelectedListener(this);
// Open first menu item
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
// Set first item checked
navigationView.setCheckedItem(R.id.nav_home);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
final MenuItem menuItem = item;
// Check if menu item is selected
if (item.isChecked())
item.setChecked(false);
else
item.setChecked(true);
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_home) {
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentHome())
.commit();
} else if (id == R.id.nav_about) {
toolbar.setTitle("About");
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentAbout())
.addToBackStack(null)
.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}}
FragmentHome
public class FragmentHome extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(R.string.fragment_home_title);
}
}
FragmentAbout code is same as FragmentHome just layout change.
I have searched a lot on stackoverflow but didn't find any solution yet, so if someone know how to do this please tell me.
There is a OnBackStackChangedListener that you can use for this. Tried it and it works great.
public Fragment getCurrentFragment() {
return this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
...
this.getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
Fragment current = getCurrentFragment();
if (current instanceof MyFragmentA) {
navigationView.setCheckedItem(R.id.nav_myfragA);
} else {
navigationView.setCheckedItem(R.id.nav_myfragB);
}
}
});
...
}
This might not be a good solution, but at least it is acceptable for me. You need to store fragment's position inside stack variable (ex: List) whenever a fragment menu is clicked from nav drawer. Then override onBackPressed to remove the last value from stack, and set drawer position to the current last value of stack. Here's the example:
private List<Integer> itemPositionStacks = new ArrayList<>();
protected void onCreate(#Nullable Bundle savedInstanceState) {
itemPositionStacks.add(currentSelectedPosition);
}
public void onNavigationViewItemSelected(int itemId) {
Fragment fr = null;
switch (itemId) {
case 0:
fr = new aFragment();
break;
case 1:
fr = new bFragment();
break;
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fr)
.addToBackStack(null)
.commit();
Drawer.getInstance().setDrawerChecked(itemId);
itemPositionStacks.add(itemId);
}
public void onBackPressed() {
if(itemPositionStacks.size() > 1) {
itemPositionStacks.remove(itemPositionStacks.size() - 1);
Drawer.getInstance().setDrawerChecked(itemIdStacks.get(itemIdStacks.size() - 1));
}
super.onBackPressed();
}
In your onBackPressed() function ..
you must choose which item to be selected by using
drawer.setCheckedItem(R.id.nav_home);
and remove the selection of the another item
drawer.getMenu().findItem(R.id.nav_about).setChecked(false);
When i switch between fragments in Navigation-drawer, Navigation-drawer closes slowly , i assume it waits to replace the newly selected fragment and closes the drawer,
How can i speed up it? In Gmail app, when you select a tab in Navigation-drawer,the new fragment is not created immediately,instead it shows a ProgressBar,then content is load,Also Navigation-drawer closing is speed here.
How can i do it, Any code example is appreciated.
Edit
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
.....
navigationDrawerTitles = getResources().getStringArray(R.array.navigation_drawer_titles);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, navigationDrawerTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
.......
}
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) {
switch(position){
case 0:
getFragmentManager().beginTransaction()
.replace(R.id.content_frame, new HomeFragment(), "HomeFragment").commit();
mDrawerList.setItemChecked(position, true);
setTitle(navigationDrawerTitles[position]);
break;
case 1:
getFragmentManager().beginTransaction()
.replace(R.id.content_frame, new HistoryFragment(), "HistoryFragment").commit();
mDrawerList.setItemChecked(position, true);
setTitle(navigationDrawerTitles[position]);
break;
case 2:
Intent sintent = new Intent(MainActivity.this,
SettingsActivity.class);
startActivity(sintent);
break;
default:
break;
}
mDrawerLayout.closeDrawer(mDrawerList);
}
Thanks,
I think this link will help you: Speed up Android Navigation drawer
public boolean smoothSlideViewTo(... int duration) {
...
return forceSettleCapturedViewAt(... int duration);
}
You have to close drawer when you replace fragment like this:
if (drawerLayout.isDrawerOpen(Gravity.START)) {
drawerLayout.closeDrawers();
}else{
drawerLayout.openDrawer(Gravity.START);
}
// your code to replace or add fragment
NOTE:- Change Gravity.START to Gravity.END if your drawer is open from right side. first close drawer and then replace fragment
I copied a navigation drawer from
http://javatechig.com/android/navigation-drawer-android-example
But I'm having trouble managing the fragments, or rather the main content on the screen.
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = "Formulas";
getActionBar().setTitle(mTitle);
// Getting reference to the DrawerLayout
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.drawer_list);
// Getting reference to the ActionBarDrawerToggle
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open,
R.string.drawer_close) {
/** Called when drawer is closed */
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
}
/** Called when a drawer is opened */
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle("Formulas");
invalidateOptionsMenu();
}
};
// Setting DrawerToggle on DrawerLayout
mDrawerLayout.setDrawerListener(mDrawerToggle);
// Creating an ArrayAdapter to add items to the listview mDrawerList
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getBaseContext(),
R.layout.drawer_list_item, getResources().getStringArray(R.array.menus));
// Setting the adapter on mDrawerList
mDrawerList.setAdapter(adapter);
// Enabling Home button
getActionBar().setHomeButtonEnabled(true);
// Enabling Up navigation
getActionBar().setDisplayHomeAsUpEnabled(true);
// Setting item click listener for the listview mDrawerList
mDrawerList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Getting an array of rivers
String[] menuItems = getResources().getStringArray(R.array.menus);
// Currently selected river
mTitle = menuItems[position];
// Creating a fragment object
WebViewFragment rFragment = new WebViewFragment();
// Passing selected item information to fragment
Bundle data = new Bundle();
data.putInt("position", position);
data.putString("url", getUrl(position));
rFragment.setArguments(data);
// Getting reference to the FragmentManager
FragmentManager fragmentManager = getFragmentManager();
// Creating a fragment transaction
FragmentTransaction ft = fragmentManager.beginTransaction();
// Adding a fragment to the fragment transaction
ft.replace(R.id.content_frame, rFragment);
// Committing the transaction
ft.commit();
// Closing the drawer
mDrawerLayout.closeDrawer(mDrawerList);
}
});
}
protected String getUrl(int position) {
switch (position) {
case 0:
return "http://javatechig.com";
case 1:
return "http://javatechig.com/category/android/";
case 2:
return "http://javatechig.com/category/blackberry/";
case 3:
return "http://javatechig.com/category/j2me/";
case 4:
return "http://javatechig.com/category/sencha-touch/";
case 5:
return "http://javatechig.com/category/phonegap/";
case 6:
return "http://javatechig.com/category/java/";
default:
return "http://javatechig.com";
}
}
How do I manage the fragment so that I can:
- Input either basic xml/java (so I don't have to bother about bundles) in the project
or
- replace the current fragment so that I can create my own and customize everything myself
Try Checking this answer ..
It ll help you setting-up & using the Navigation Drawer in a dynamic way...
https://stackoverflow.com/a/34244065/2457493
Hope this fulfills you query..
I assume this is the example code from the Android Project shipped with the SDK.
Your sample actually contains the code needed for swapping the fragments in the content pane of the Activity.
// Getting reference to the FragmentManager
FragmentManager fragmentManager = getFragmentManager();
// Creating a fragment transaction
FragmentTransaction ft = fragmentManager.beginTransaction();
// Adding a fragment to the fragment transaction
ft.replace(R.id.content_frame, rFragment);
// Committing the transaction
ft.commit();
Your rFragment is the fragment that is going to be loaded. You can put this whole section in a method and pass your fragment to be loaded as an argument of that method, e.g.
private void replaceFragment(Fragment newFragment) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, newFragment);
ft.commit();
}
If your Fragment to be loaded needs data to be passed to it, you can use the Bundle. Your fragments might take different types of data, but the code above still applies. Call it after you have called setArguments() on your Fragment object.