I have a Activity with four buttons at the bottom like tabs. By pressing any button a new Fragment is displayed in the FrameLayout above these buttons like we do in TabActivity. See My Problem here .Now i think i should find a way to hide and show those fragments. Kindly tell me how can i show and hide a fragment without reloading it again.
Main Purpose of showing hiding a fragment is to maintain its current state. In one of my fragment i have an AsyncTask whenever i switch between fragment it call that AsynTask again.
// to show fragment when it is hidden
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.show(fragment1)
.commit();
// to hide fragment
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.hide(fragment1)
.commit();
you can't pass by some view like
declare 4 frameLayout
private FrameLayout fragment1;
private FrameLayout fragment2;
private FrameLayout fragment3;
private FrameLayout fragment4;
and
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment1, Fragment1.newInstance());
ft.replace(R.id.fragment2, Fragment2.newInstance());
ft.replace(R.id.fragment3, Fragment3.newInstance());
ft.replace(R.id.fragment4, Fragment4.newInstance());
ft.commit();
and play with visible or gone ? like
fragment1.setVisibility(View.Visible);
fragment2.setVisibility(View.gone);
fragment3.setVisibility(View.gone);
fragment4.setVisibility(View.gone);
and by the way : works for me ->
public class Activity extends ActionBarActivity {
private FrameLayout fragment1;
private FrameLayout fragment2;
private Button bt1;
private Button bt2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.frg_test_frg);
fragment1 = (FrameLayout) findViewById(R.id.fragment1);
fragment2 = (FrameLayout) findViewById(R.id.fragment2);
bt1 = (Button) findViewById(R.id.button);
bt2 = (Button) findViewById(R.id.button2);
bt1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragment1.setVisibility(View.VISIBLE);
fragment2.setVisibility(View.GONE);
}
});
bt2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragment1.setVisibility(View.GONE);
fragment2.setVisibility(View.VISIBLE);
}
});
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment1, new Fragment1());
ft.replace(R.id.fragment2, new Fragment2());
ft.commit();
}
Related
I have a series of fragments. And I use "previous" and "next" buttons for navigation within this fragments. There are many edit texts and radio buttons in this fragments.
I want to save and and restore the user input in these edit texts and radio buttons when a previous fragment is loaded by clicking on "previous" button.
Screeshots:
Fragment 1
Fragment 2
Fragment 1:
public class Register_Page6 extends Fragment {
public Register_Page6() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_register_page6, container, false);
Button Previous = (Button) view.findViewById(R.id.Previous6);
Button Next = (Button) view.findViewById(R.id.Next6);
Next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
android.support.v4.app.FragmentTransaction FT;
FT = getActivity().getSupportFragmentManager().beginTransaction();
FT.replace(R.id.main_container,new Register_Page7());
FT.commit();
}
});
Previous.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
android.support.v4.app.FragmentTransaction FT;
FT = getActivity().getSupportFragmentManager().beginTransaction();
FT.replace(R.id.main_container,new Register_Page5());
FT.commit();
}
});
return view;
}
}
Fragment 2:
public class Register_Page7 extends Fragment {
public Register_Page7(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_register_page7, container, false);
Button Previous = (Button) view.findViewById(R.id.Previous7);
Button Regiter = (Button) view.findViewById(R.id.Submit);
Regiter.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
android.support.v4.app.FragmentTransaction FT;
FT = getActivity().getSupportFragmentManager().beginTransaction();
FT.replace(R.id.main_container,new Register_Page6());
FT.commit();
}
});
Previous.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
android.support.v4.app.FragmentTransaction FT;
FT = getActivity().getSupportFragmentManager().beginTransaction();
FT.replace(R.id.main_container,new Register_Page6());
FT.commit();
}
});
return view;
}
}
Add Your fragment to back stack using addToBackStack("YOUTAG") like this in all your fragments :
android.support.v4.app.FragmentTransaction FT;
FT = getActivity().getSupportFragmentManager().beginTransaction();
FT.replace(R.id.main_container, new Register_Page6()).addToBackStack("FragmentName");
FT.commit();
When you have a series of fragments if you add them to the backstack it would be memory wastage.
For this kind of action android provides something called ViewPager, which will always store 2 fragments at a time and create the rest of fragments dynamically when needed.
So if you still decided you don't want to use ViewPager, you can store the Fragment's data in activity's bundle and you can retrieve data when creating the fragment again
all!
I have 2 fragments. First one appears at start, second one adds with button "Add", using the same container.I am trying to add fragment to the back stack with method addToBackStack, but when I click "back-button" my app hides instead of showing me the first fragment. What is wrong?
public class MainActivity extends AppCompatActivity {
FirstFragment fragment1;
SecondFragment fragment2;
FragmentTransaction fragmentTransaction;
FragmentManager fm;
Button add;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
fragment1 = new FirstFragment();
fragment2 = new SecondFragment();
add = (Button) findViewById(R.id.add);
fm = getFragmentManager();
fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.container, new FirstFragment());
fragmentTransaction.commit();
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.container, new SecondFragment());
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
}
}
addToBackStack() on fragment transaction is not enough, we have to handle the popping up of the back stack upon Back button pressed by ourselves.
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
Hi guys im working on my MainActivity and I am dealing with the following problem:
In my MainActivity I have 3 buttons(button1, button2, button3). With each I can add a Fragment(Fragment2, Fragment1, ProfileFragment) to my container. Everytime a button is pressed, it checks the Fragments if there is already anotherone visible.
If yes, FragmentManager().beginnTransaction().fragment.hide() should hide it.
Then it checks if the fragment bound to the button already exists.
If no, it adds it.
If yes, it should make the existing hidden fragment visible again with FragmentManager().beginnTransaction().fragment.show()
Now: If I press button2 as the first when I start my App everything works fine and I can infinitely switch between the fragments.
But: If I press button1 as the first, and then switch to button2 or button3, the fragment bound to button1 (m2fragment) can't be shown again. It just shows m1fragment (which should be hidden when I press button1)
The same happens if I press button3 as the first. Everytime I try to switch back to button3(profileFragment) it just shows m1fragment.
May be there a problem with the googleMap which I call from the xml from m2Fragment??
Anyone can see where I made (a) mistake(s) ? I would be really glad since I am dealing with this for several days now.
Thank you all !
Cut from my MainActivity:
public class MainActivity extends FragmentActivity implements ProfileFragment.OnFragmentInteractionListener,
OfferFragment.OnFragmentInteractionListener, MapsFragment.OnFragmentInteractionListener, OpenerFragment.OnFragmentInteractionListener, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
protected int fragment1Open = 0;
protected int fragment2Open = 0;
protected int profileFragmentOpen = 0;
Fragment1 m1Fragment = new Fragment1();
Fragment2 m2Fragment = new Fragment2();
ProfileFragment mProfileFragment = new ProfileFragment();
OpenerFragment mOpenerFragment = new OpenerFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState==null) {
getFragmentManager().beginTransaction().add(R.id.container,mOpenerFragment).commit();
}
final Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//check fragments
if(mOpenerFragment.isVisible()) {
getFragmentManager().beginTransaction().remove(mOpenerFragment).commit();
Log.d("button1", "remove OpenerFragment");
}
if(m1Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m1Fragment).commit();
}
if(mProfileFragment.isVisible()) {
getFragmentManager().beginTransaction().hide(mProfileFragment).commit();
}
if(fragment2Open==0) {
fragment2Open=1;
getFragmentManager().beginTransaction().add(R.id.container, m2Fragment).commit();
} else {
getFragmentManager().beginTransaction().show(m2Fragment).commit();
}
}
});
final Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//hide other fragments
if(mOpenerFragment.isVisible()) {
getFragmentManager().beginTransaction().remove(mOpenerFragment).commit();
}
if(mProfileFragment.isVisible()) {
getFragmentManager().beginTransaction().hide(mProfileFragment).commit();
}
if(m2Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m2Fragment).commit();
}
if(fragment1Open==0) {
fragment1Open=1;
getFragmentManager().beginTransaction().add(R.id.container, m1Fragment).commit();
} else {
getFragmentManager().beginTransaction().show(m1Fragment).commit();
}
}
});
final Button button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//hide other fragments
if(mOpenerFragment.isVisible()) {
getFragmentManager().beginTransaction().remove(mOpenerFragment).commit();
}
if(m1Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m1Fragment).commit();
}
if(m2Fragment.isVisible()) {
getFragmentManager().beginTransaction().hide(m2Fragment).commit();
}
//open fragment
if(profileFragmentOpen==0) {
profileFragmentOpen=1;
getFragmentManager().beginTransaction().add(R.id.container, mProfileFragment).commit();
} else {
getFragmentManager().beginTransaction().show(mProfileFragment).commit();
}
}
});
mProfileFragment and m2Fragment use identically onCreate and onCreateView methods:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.fragment_profile, container, false);
return rootview;
}
m1Fragment has the same methods, but gets a googleMaps fragment from its xml file.
m1Fragment:
public class Fragment1 extends Fragment implements OnMapReadyCallback {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MapFragment mapFragment=(MapFragment) getFragmentManager().findFragmentById(mapid);
if (mapFragment==null) {
mapFragment = MapFragment.newInstance();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.container, mapFragment);
fragmentTransaction.commit();
mapFragment.getMapAsync(this);
}
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap map) {
//right upper corner, location layer activated
map.setMyLocationEnabled(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_maps, container, false);
return rootView;
}
fragment_1.xml:
<fragment
android:id="#id/mapid"
class="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
MapFragment mapFragment=(MapFragment) getFragmentManager().findFragmentById(mapid);
in this line your actually tring to get the parent's fragmentManager (in your case the activity),and fail to find the fragment.
and then in this line:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.container, mapFragment);
fragmentTransaction.commit();
you are adding to the parent FragmentManager.
a quick to solution is to replace getFragmentManger() with getChildFragmentManager, which refers to the fragment's FragmentManager.
Maybe you should try to use :
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack if needed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
With fragment_container as FrameLayout in your activity?
I'm not 100% sure, but i think it'll avoid such issues
I just solved it:
Withing my MapsFragment class I instantiated a googleMaps fragment "twice". Trying to hide the mapFragment I just hid one of them, leaving the other one visible in front.
For people having similar issues here my solution:
I erased the
<fragment
android:id="#id/mapid"
class="com.google.android.gms.maps.MapFragment"/>
from the xml layout file.
And inside the MapsFragment class I changed
MapFragment mapFragment=(MapFragment) getChildFragmentManager().findFragmentById(mapid);
to
MapFragment mapFragment = MapFragment.newInstance();
getChildFragmentManager().beginTransaction().add(R.id.framLay, mapFragment).commit();
Now I put one clean Instance of MapFragment into my FrameLayout and it works properly.
How do I switch fragments inside a tab?
My application contains three fragments, AFragment, BFragment, and CFragment. These fragments, in turn, correspond to their own layout files: AFragment contains a Button, and BFragment and CFragment have TextView. There is a fourth layout file named activity_main.
Now, I have four classes, MainActivity, AFragment, BFragment and CFragment. The classes AFragment, BFragment, CFragment only the typical contain OnCreateView on each of them.
MainActivity contains this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
appContext = getApplicationContext();
//ActionBar
ActionBar actionbar = getActionBar();
actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab PlayerTab = actionbar.newTab().setText("Fragment A");
ActionBar.Tab StationsTab = actionbar.newTab().setText("Fragment B");
Fragment PlayerFragment = new AFragment();
Fragment StationsFragment = new BFragment();
PlayerTab.setTabListener(new MyTabsListener(PlayerFragment));
StationsTab.setTabListener(new MyTabsListener(StationsFragment));
actionbar.addTab(PlayerTab);
actionbar.addTab(StationsTab);
And then the TabListener:
class MyTabsListener implements ActionBar.TabListener {
public Fragment fragment;
public MyTabsListener(Fragment fragment) {
this.fragment = fragment;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
Toast.makeText(MainActivity.appContext, "Reselected!", Toast.LENGTH_LONG).show();
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.replace(R.id.fragment_container, fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(fragment);
}
}
As you can see, activity_main.xml only contains a LinearLayout with an id 'fragment_container' for tabs AFragment and BFragment. Now I want it in such a way that clicking a button in AFragment switches the entire AFragment to CFragment. How can I achieve this? Thank you.
(EDIT) I did the following but my app crashed on start. What did I do wrong?
I added the following on my MainActivity.java, just below the ActionBar sequence:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
appContext = getApplicationContext();
//ActionBar
....
....
....
Button mButton = (Button) findViewById(R.id.button1);
mButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
CFragment fragment = new CFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
});
get a fragment transaction using the (support) fragment manager of your activity.
replace AFragment by CFragment as you did in onTabSelected
commit your transaction.
Also, please note :
don't keep references on your fragment, you actually prevent garbage collection from occuring. You should create your fragments once, not every time. In TabSelected, check if the fragment is known by the fragment manager (using findFragmentByTag). If not, create it. If it is, just re-replace it.
share your listener, you don't need one by tab.
public class MainActivity extends FragmentActivity {
FragmentTransaction ft;
Button b1, b2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
ft.replace(android.R.id.content, new Fragment1());
} else {
ft.add(R.id.LinearLayout1, new MainFragment());
ft.add(R.id.LinearLayout2, new Fragment1());
}
ft.commit();
}
}
public class MainFragment extends Fragment implements OnClickListener{
Button b1,b2;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.activity_main_fragment, container, false);
}
#Override
public void onStart() {
super.onStart();
// ---Button view---
b1 = (Button) getActivity().findViewById(R.id.f1);
b2 = (Button) getActivity().findViewById(R.id.f2);
b1.setOnClickListener(this);
b2.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v==b1){
FragmentManager fm = getActivity().getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.LinearLayout2,new Fragment2());
ft.commit();
}
if(v==b2){
FragmentManager fm =getActivity().getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.LinearLayout2,new Fragment3());
ft.commit();
}
}
}
The problem here when the application is running in portrait mode the Fragment1 appear as i want and when i change the orientation to landscape ,the MainFragment and Fragment2 appear as i want too but Fragment1 still there,
and when i change orientation again to portrait ,the application stopped.
How can I solve it?
So the problem is you are assuming that every time onCreate is called you are starting out with no fragments...which is not the case.
The first time onCreate is called for MainActivity there will be no fragments. Assuming the device was in portrait, Fragment1 will be added. When you rotate to landscape then another instance of Fragment1 will be added and an instance of MainFragment. You now have three fragment instances. When you go back to portrait its going to want to add ANOTHER instance of Fragment1...but it is probably crashing because the portrait layout doesn't have R.id.LinearLayout1 or R.id.LinearLayout2.
Bottom line is...you need to remove fragments once you are done with them...they don't just go away by themselves.