I've added a Navigation drawer activity to my project and I'm trying to add items as fragments. This is what I have done in the main activity.
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.nav_host_fragment, new HomeFragment());
fragmentTransaction.commit();
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item)
{
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
int id = item.getItemId();
if (id == R.id.nav_home)
{
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.nav_host_fragment, new HomeFragment());
fragmentTransaction.commit();
}
else if(id == R.id.Shopping_list)
{
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.nav_host_fragment, new ShoppingListFragment());
fragmentTransaction.commit();
}
else if(id == R.id.nav_Language)
{
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.nav_host_fragment, new FragmentLang());
fragmentTransaction.commit();
}
The default fragment is Home which is working fine and as expected BUT the other fragments are overlapping with the Home Fragment. (The HomeFragment is the only one that's working fine).
I've done something like this inside every Fragment class:
public class ShoppingListFragment extends Fragment{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.fragment_shopping_list, container,false);
return view;
}
}
I can't see where the mistake is. everything looks good but all other fragments are showing over the HomeFragment.
fragment manager maintains the stack of all the previous fragments that are replaced sometimes the back stack fragments overlap with the fragment we replaced, add this line
fragmentManager.popBackStack();
like this,
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.nav_host_fragment, new HomeFragment());
fragmentManager.popBackStack();
fragmentTransaction.commit();
Hope will help. Happy coding :)
Related
This use Navigation Drawer, and use Tab, and use Fragment.
MainActivity.java
public class MainActivity extends AppCompatActivity {
DrawerLayout myDrawerLayout;
NavigationView myNavigationView;
FragmentManager myFragmentManager;
FragmentTransaction myFragmentTransaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
myNavigationView = (NavigationView) findViewById(R.id.nav_drawer) ;
myFragmentManager = getSupportFragmentManager();
myFragmentTransaction = myFragmentManager.beginTransaction();
myFragmentTransaction.replace(R.id.containerView, new HomeFragment()).commit();
myNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem selectedMenuItem) {
myDrawerLayout.closeDrawers();
if (selectedMenuItem.getItemId() == R.id.nav_item_select1) {
FragmentTransaction fragmentTransaction = myFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView, new Select1()).commit();
}
return false;
}
}
}
}
Pyeondo.java
You have to use same fragment in which you are setting bundle.
Replace new select1() with fragment
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
bundle.putString("Slocale1",SbtnsLocale.getText().toString());
bundle.putString("Slocale2",SbtneLocale.getText().toString());
bundle.putString("Sdate1",StxtsDate.getText().toString());
bundle.putString("Sdate2",SStxtsDate.getText().toString());
bundle.putString("Sseat",StxtSeat.getText().toString()); // use as per your need
fragment.setArguments(bundle);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.containerView, fragment).commit();
You already has fragment instance
fragment.setArguments(bundle);
and you are setting argument in that instance so don't create new one, use it
fragmentTransaction.replace(R.id.containerView, fragment).commit();
From my main activity, pressing Settings button opens an AppCompatActivity with FrameLayout as the container for the fragments. In OnCreate method, I'm adding the fragment which is a PreferenceScreen container.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.custom_toolbar);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
ab.setTitle("Settings");
}
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = null;
if (savedInstanceState == null) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragment = SettingsFragment.newInstance(null);
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
}
Pressing again another button called Options, opens replaces fragment with Options fragment adding the current class to backstack.
#Override
public boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref) {
FragmentManager manager = getSupportFragmentManager();
SettingsSubscreenFragment fragment = null;
Bundle args = new Bundle();
switch (pref.getKey()) {
case "pref_key_rejection_options":
getSupportActionBar().setTitle("Rejection Options");
fragment = SettingsSubscreenFragment.newInstance("Options");
break;
}
args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, pref.getKey());
if (fragment != null) {
fragment.setArguments(args);
}
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.fragment_container, fragment, pref.getKey());
ft.addToBackStack(null);
ft.commit();
return true;
}
When I press the Up Button, I'm just replacing the Options fragment to the first fragment, Settings, which does not pop the back stack.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getSupportActionBar().setTitle("Settings");
FragmentManager fragmentManager;
FragmentTransaction ft;
Fragment fragment = null;
if (getSupportFragmentManager().findFragmentByTag("pref_key_options") != null) {
fragmentManager = getSupportFragmentManager();
ft = fragmentManager.beginTransaction();
fragment = SettingsFragment.newInstance(null);
ft.replace(R.id.fragment_container, fragment);
ft.commit();
fragmentManager.getFragments().clear();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
return super.onOptionsItemSelected(item);
}
So, opening the Options fragment again will add another to back stack and onBackPress, it only pops the topmost and leaves its shadow overlapping the other one registered in back stack.
#Override
public void onBackPressed() {
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
if (backStackCount >= 1) {
getSupportActionBar().setTitle("Settings");
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
The almost the same situation is like from here, third picture of the question, but I can't make it work with their suggestions.
What am I doing wrong and what I can do to make this work? Thanks a lot.
Check FragmentTransaction , SettingsSubscreenFragment and SettingsFragmentare extending android.support.v4.app.Fragment . If not , try
class YourFragments extends android.support.v4.app.Fragment
in your fragment classes.
My current Android application has two Fragments:-
ListFragment
Detailfragment
My Layout XML resembles:-
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_anchorGravity="bottom"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</FrameLayout>
I display the ListFragment first as follows:-
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(containerId, mListFragment, LIST_FRAGMENT_TAG);
if (mLandscape) {
} else {
fragmentTransaction.addToBackStack(LIST_FRAGMENT_TAG);
}
fragmentTransaction.commit();
When the user clicks on a List item, I want to hide the List so that I keep the current list position etc.. and display the detailFragment.
Heres the code I use to perform this UI change:-
mDetailFragment = new DetailFragment();
final Bundle fragmentArguments = new Bundle();
fragmentArguments.putString(ITEM_KEY, item.getKey());
mDetailFragment.setArguments(fragmentArguments);
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (mLandscape) {
fragmentTransaction.replace(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
} else {
fragmentTransaction.hide(mListFragment);
fragmentTransaction.add(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
}
fragmentTransaction.commit();
The above code all works fine and I can transition between the List and Detail Fragments successfully.
The issue I have is that when the user presses the BACK BUTTON on the detail Fragment to return to the ListFragment they return to a blank screen.
I have this code in my Activity to remove the detail fragment and show the hidden List fragment:-
#Override
public void onBackPressed() {
if (mLandscape) {
} else {
if (mListFragment.isHidden()) {
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(mDetailFragment);
fragmentTransaction.show(mListFragment);
fragmentTransaction.commit();
}
}
super.onBackPressed();
}
Why is fragmentTransaction.show(mListFragment); not showing the hidden ListFragment?
NOTE: So that I always rebuild my ui completely on orientation changes I have passed a null bundle to super.onCreate(savedInstanceStateNull);
private final Bundle savedInstanceStateNull = null;
private boolean mLandscape = false;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceStateNull);
setContentView(R.layout.activity_article_list);
mLandscape = getResources().getBoolean(R.bool.landscape);
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
manageFragments();
}
Heres how I fixed this issue:-
First remove my overriden onBackPressed()
Change display ListFragment to this:-
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(containerId, mListFragment, LIST_FRAGMENT_TAG);
fragmentTransaction.commit();
Change display detailFragment to this:-
mDetailFragment = new DetailFragment();
final Bundle fragmentArguments = new Bundle();
fragmentArguments.putString(ITEM_KEY, item.getKey());
mDetailFragment.setArguments(fragmentArguments);
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (mLandscape) {
fragmentTransaction.replace(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
} else {
fragmentTransaction.hide(mListFragment);
fragmentTransaction.add(containerId, mDetailFragment, DETAIL_FRAGMENT_TAG);
fragmentTransaction.addToBackStack(DETAIL_FRAGMENT_TAG);
}
fragmentTransaction.commit();
Recently i'm working on my app to make it load faster and work better, i'm using navigation drawer in my MainActivity:
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camara) {
LoadJson asyncTask = (LoadJson) new LoadJson(new LoadJson.AsyncResponse() {
#Override
public void processFinish(JSONArray output) {
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
//Set the fragment initially
MainFragment fragment = new MainFragment(output);
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
// Handle the camera action
}
}).execute();
} else if (id == R.id.nav_gallery) {
//Set the fragment initially
GalleryFragment fragment = new GalleryFragment();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
} else if (id == R.id.nav_search) {
//Set the fragment initially
FetchResualt fragment = new FetchResualt();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
// Handle the camera action
} else if (id == R.id.nav_manage) {//
Bundle bundle = new Bundle();//
bundle.putInt("someStr",ID_OF_BEACH);//
//Set the fragment initially//
FragmentBeach fragment = new FragmentBeach();//
fragment.setArguments(bundle);//
FragmentTransaction fragmentTransaction =//
getSupportFragmentManager().beginTransaction();//
fragmentTransaction.replace(R.id.fragment_container, fragment);//
fragmentTransaction.commit();//
// Handle the camera action
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
As you can see if we push the first menu if (id == R.id.nav_camara) it will pass a JSONArray to a Fragment class and it take like 4-5 seconds to load. So if the user navigates between menus every time he goes to nav_camara it make the app a 4 second freeze to load and as you can see everytime we choose a menu item it will recreate a new copy of fragment, so even if I make: setRetainInstance(true); in my fragment class it wont work.
What solution you suggest to prevent the app to recreate a new fragment each time we choose a menu item?
You will need to keep a SparseArray<Fragment> to keep the instances in memory.
Follow these steps:
create a field in your Activity:
SparseArray<Fragment> myFragments;
initialise it in the onCreate() like:
myFragments = new SparseArray<Fragment>();
update your onNavigationItemSelected():
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camara) {
// get cached instance of the fragment
fragment = myFragments.get(INT_CONSTANT_FOR_CAM_FRAGMENT);
// if fragment doesn't exist in myFragments, create one and add to it
if (fragment == null) {
fragment = new MainFragment();
myFragments.put(INT_CONSTANT_FOR_CAM_FRAGMENT, fragment);
}
// now load the fragment
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
// do the rest with others as well.
}
move the AsyncTask thing inside your MainFragment's onActivityCreated() or a similar lifecycle method.
Above way will let you reuse the fragments and move the logic to their correct location (your Activity shouldn't know how MainFragment loads data to initiate itself, but of course you can still keep it there, though not recommended).
You can add a TAG while push a new fragment to the container. Then use FragmentManager#findFragmentByTag to find any fragment previously added with the same tag.
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
Fragment oldFragment = manager.findFragmentByTag(tag);
if (oldFragment != null)
transaction.replace(R.id.fragment_container, oldFragment, tag);
else
transaction.replace(R.id.fragment_container, newInstanceOfFragment, tag);
transaction.commit();
Declare them globally
GalleryFragment galleryFrag = new GalleryFragment();
FragmentTransaction ft;
FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
fm = getSupportFragmentManager();
...
}
then on your navigation selection
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_search) {
ft = fm.beginTransaction();
ft.replace(R.id.fragment_container, galleryFrag).commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
I am new to android working first time on fragment.I am creating an app in which I want to add a fragment on frame layout.I am able to do this but now what I want is to remove the same fragment which i added by that same button click I tried but couldn't. here is my code.
public void onClick(View v) {
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
if(v.getId() == R.id.clickme){
if(getSupportFragmentManager().findFragmentById(R.layout.fragment_one) != null){
// getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.layout.fragment_one)).commit();
Fragment fragment = new FragmenOne();
fragmentManager.beginTransaction().remove(fragment).commit();
}else{
Fragment fragment = new FragmenOne();
// android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.my_frame, fragment)
.commit();
}
}
}
You need to do in this manner
Fragment f = fragmentManager.findFragmentById(R.id.my_frame);
if(f instanceof FragmenOne) {
FragmenOne oneFragment = (FragmenOne) f;
FragmentTransaction trans = manager.beginTransaction();
trans.remove(oneFragment);
trans.commit();
fragmentManager.popBackStack();
}else{
Fragment fragment = new FragmenOne();
fragmentManager.beginTransaction()
.replace(R.id.my_frame, fragment)
.commit();
}