I want to achieve below concept in android:-
Tab A -> Fragment A -> Fragment 1 -> Fragment 2
Tab B -> Fragment B
Tab C -> Fragment C
Tab D -> Fragment D
I am adding tabs on view pager and able to achieve till
Tab A -> Fragment A
Tab B -> Fragment B
Tab C -> Fragment C
Tab D -> Fragment D
I tried with
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.content, fragment1);
ft.addToBackStack(null);
ft.commit();
but not able to add another fragment on Fragment A.
it is adding fragment 1 upon Fragment A but Fragment A is still visible in background. So please provide some suggestion to achieve above task.
Thanks in Advance.
It's mine. Hope it's helpful.
First, you need to create the ContentFragment for 4 tabs A, B, C, D like below:
public class ContentFragmentA extends BaseFragment {
private static Context context;
#SuppressWarnings("static-access")
public ContentFragmentA(Context context) {
super();
this.context = context;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.content_frame_a, container, false);
this.setFragmentManager(getChildFragmentManager());
this.setContainerId(R.id.content_frame_a);
this.replaceFragmentIntoStack(new FragmentOne(context), "FragmentOne");
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}}
Then, create the content_fragment_a.xml file
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/content_frame_a"
android:layout_width="match_parent"
android:layout_height="match_parent" >
Then, for each new fragment you should extends BaseFragment. And when if you want to put new fragment into tab, just use addFragmentIntoStack(), or replaceFragmentIntoStack().
public class BaseFragment extends Fragment{
private FragmentManager fragmentManager;
private int containerId;
private boolean doubleBackToExit = false;
/**
* #param containerId the containerId to set
*/
public void setContainerId(int containerId) {
this.containerId = containerId;
}
/**
* #param fragmentManager the fragmentManager to set
*/
public void setFragmentManager(FragmentManager fragmentManager) {
this.fragmentManager = fragmentManager;
}
/**
*
*/
public BaseFragment() {
super();
// TODO Auto-generated constructor stub
BarddyApplication.getInstance().baseFragment = BaseFragment.this;
}
public void addFragmentIntoStack(BaseFragment newContent, String tagName) {
newContent.setFragmentManager(fragmentManager);
newContent.setContainerId(containerId);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(containerId, newContent, tagName);
fragmentTransaction.addToBackStack(tagName);
fragmentTransaction.commitAllowingStateLoss();
}
public void popFragment() {
fragmentManager.popBackStack();
}
public void replaceFragmentIntoStack(BaseFragment newContent, String tagName) {
newContent.setFragmentManager(fragmentManager);
newContent.setContainerId(containerId);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(containerId,newContent,tagName);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commitAllowingStateLoss();
}}
Very simple!
Fist you need to fragment A blank and then you need create new three fragment:
Fragment A1, fragment 1, fragmen2
And now when you chose tab A, you show fragment A1 in fragment A
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction.replace(R.id.category_fragment, new CategoryFragment());
transaction.commit();
Now you can use method replace() fragment 1 or 2 to id of Fragment A (not id of A1) to replace A1 with fragment 1 or 2.
Hope it help you!
Related
I am making a simple demo project using Fragments, in which i am calling SecondFragment from FirstFragment on button click.
And i called SecondFragment without any issue, but i getting view of both the Fragments SecondFragment and FirstFragment
So where i am doing mistake ?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new FirstFragment()).commit();
}
}
public static class FirstFragment extends Fragment {
Button buttonCallSecondFragment;
public FirstFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_first, container,
false);
buttonCallSecondFragment = (Button) rootView.findViewById(R.id.button1);
buttonCallSecondFragment.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
FragmentManager fm = getFragmentManager();
SecondFragment fragment = new SecondFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.container, fragment);
ft.commit();
}
});
return rootView;
}
}
public static class SecondFragment extends Fragment {
public SecondFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_second, container,
false);
return rootView;
}
}
}
You need to remove the first fragment, you can do that either by usingreplace or first calling remove then add
To be able to press the back button add the transaction to the back stack,you do that by calling addToBackStack(tag) on your fragment manager. Tag may be null.
You are adding fragment on already displaying fragment in your android app.
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.container, fragment);
ft.commit();
Do not add fragment but replace fragment when already one fragment is loaded on activity.
So for implementing that :
Please add your code in OnCreate() and add below code to your click listener :
FragmentManager fm = getFragmentManager();
SecondFragment fragment = new SecondFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container, fragment);
ft.addToBackStack(null);
ft.commit();
Thank you.!!
if you want to replace fragment you should call replace in place of add :
buttonCallSecondFragment = (Button) rootView.findViewById(R.id.button1);
buttonCallSecondFragment.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
FragmentManager fm = getFragmentManager();
SecondFragment fragment = new SecondFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
}
});
You are adding the fragment so it will come on top of another fragment give background color to rootview of scecond fragment
you can also load that as Nested fragment
public void addFragB() {
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
SecondFragment 2ndfrag = new SecondFragment();
childFragTrans.add(R.id.fragA_LinearLayout, 2ndfrag);
//childFragTrans.addToBackStack("");
childFragTrans.commit();
}
No, you cannot communicate between fragments like this. You need to communicate between fragments via the container activity.
I suggest, you make a navigation method in your activity and switch/call between fragments from there.
Below is a small snippet:
In your container activity:
Fragment fragment;
public void navigateTo(Fragment newFragment,boolean addToBackStack) {
this.fragment = newFragment;
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.fragment_container, newFragment);
if(addToBackStack)
ft.addToBackStack(fragment.getClass().getSimpleName());
ft.commit();
}
If you are going from Fragment1 to Fragment2 then in your Fragment1 do the following:
((YourContainerActivity) getActivity()).navigateTo(new Fragment2(),false); //if you want to add to back stack make 2nd argument true.
private void selectItem(int position) {
selectedPosition = position;
// update the main content by replacing fragments
fragment = null;
fragmentStack = new Stack<Fragment>();
switch (position) {
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
}
//redirect the screen
if (fragment != null) {
fragmentManager = getSupportFragmentManager();
redirectScreen(fragment);
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(title[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
}
I have two fragments that are in the main activity and i want to refresh them when something occurs.
Now the code works for second fragment, but won't work for the first, and i am not sure why.
I have been looking at the code for about an hour, and i can't seem to find a reason.
Here is the code
public class MainActivity extends FragmentActivity {
Fragment frag,frag2;
FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String screen = getString(R.string.screen_type);
/*
* Get a reference to fragment manager
* Wire the container to represent fragment
*/
fm = getSupportFragmentManager();
frag = fm.findFragmentById(R.id.container);
if(screen.equals("large")){
frag2 = fm.findFragmentById(R.id.containerDetails);
loadFragments(frag,frag2,fm);
}
/*Loads the fragment into the activity*/
else
loadFragment(frag,fm);
}
private void loadFragments(Fragment frag, Fragment frag2, FragmentManager fm) {
if(frag == null && frag2 == null){
frag = new DisplayFragment();
frag2 = new DetailsFragment();
fm.beginTransaction().add(R.id.container,frag).add(R.id.containerDetails, frag2).commit();
}
}
private void loadFragment(Fragment frag, FragmentManager fm) {
if(frag == null){
frag = new DisplayFragment();
fm.beginTransaction().add(R.id.container,frag).commit();
}
}
public void updateDetails(int position) {
// Reload current fragment
if(frag2!=null)fm.beginTransaction().remove(frag2).commit();
frag2 = new DetailsFragment();
Bundle b = new Bundle();
b.putInt("Id",position);
frag2.setArguments(b);
fm.beginTransaction().add(R.id.containerDetails, frag2).commit();
}
public void updateDisplay() {
// Reload current fragment
if(frag!=null)fm.beginTransaction().remove(frag).commit(); //THIS IS ALWAYS NULL FOR SOME REASON
frag = new DisplayFragment();
fm.beginTransaction().add(R.id.container, frag).commit();
}
public void refreshDetails() {
// Reload current fragment
if(frag2!=null)fm.beginTransaction().remove(frag2).commit();
frag2 = new DetailsFragment();
fm.beginTransaction().add(R.id.containerDetails, frag2).commit();
}
}
The first fragment is always null, and it doesn't get removed, instead another fragment is pasted over that, and creates a mess.
Try using replace() method rather than add()
Yesterday I downloaded new HoloEverywhere library.
Currently, I have problem with tab navigation after screen rotation.
My Home Activity:
public class MainActivity extends Activity implements TabListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setUpTabs();
}
private void setUpTabs() {
String[] titles = {
"First", "Second",
};
ActionBar supportActionBar = getSupportActionBar();
for (int i = 0; i < titles.length; i++) {
ActionBar.Tab tab = supportActionBar.newTab();
tab.setText(titles[i]);
tab.setTag(MyFragment.TAG);
tab.setTabListener(this);
supportActionBar.addTab(tab, false);
}
supportActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
supportActionBar.setSelectedNavigationItem(0);
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction fragmentTransaction) {
final String fragmentTag = tab.getTag().toString();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(fragmentTag);
if (fragment == null) {
fragment = new MyFragment();
fragmentTransaction.add(android.R.id.content, fragment, fragmentTag);
} else {
fragmentTransaction.attach(fragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction fragmentTransaction) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag((String) tab.getTag());
if (fragment != null) {
fragmentTransaction.detach(fragment);
}
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction fragmentTransaction) {
}
}
And my Fragment class.
public class MyFragment extends Fragment {
public static final String TAG = MyFragment.class.getCanonicalName();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = new View(getActivity());
view.setBackgroundColor(Color.BLACK);
return view;
}
}
When I rotate the screen fragment not displaying. It displays when i select tab (which is not currently selected) manually.
I just solve the problem.
I post my code here and see if those can help you :D
if (savedInstanceState == null){
TabHomeFragment homeFragment = new TabHomeFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, homeFragment, "home_fragment").commit();
}else{
TabHomeFragment homeFragment = (TabHomeFragment) getSupportFragmentManager().findFragmentByTag("home_fragment");
}
Those code are located in OnCreate method.
When the Device rotate and Ortiention change, the fragment will recreate again. So add a if clase to check if there is already one here.
But I am using normal Fragment in Android. Hope it can help you a little.
I want to display ListView in Tab (after selecting this tab I want ListView to appear),so I have created Fragment class and placed ListView code in it.The main problem now is to pass fragment object to tabListener. Please, post here example, or even better show how to do that in my code. Anyway, any help will be appreciated.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tabOne = actionBar.newTab().setText("One");
ActionBar.Tab tabTwo = actionBar.newTab().setText("Two");
tabOne.setTabListener(new tabListener());
tabTwo.setTabListener(new tabListener());
actionBar.addTab(tabOne);
actionBar.addTab(tabTwo);
}
protected class tabListener implements ActionBar.TabListener {
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
};
public class FirstFragment extends ListFragment {
private ArrayList<Cinemas> cinema;
private CinemasAdapter cinemaAdapter;
private ListView list;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
cinema = new Handler().handle();
cinemaAdapter = new CinemasAdapter(MainActivity.this, R.layout.movie_data_row, cinema);
setListAdapter(cinemaAdapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Cinemas movie = cinemaAdapter.getItem(position);
Intent intent = new Intent (MainActivity.this, More.class);
intent.putExtra("Cinemas", movie);
intent.putExtra("data", movie.getBitmap());
Bundle translateBundle =
ActivityOptions.makeCustomAnimation(MainActivity.this,
R.anim.slide_in_left, R.anim.slide_out_left).toBundle();
startActivity (intent, translateBundle);
}
}
}
If you want to open up the list inside the tabTwo, you will need to create an instance of the FirstFragment class and add it to your view when you select the tab. Inside onTabSelected, create a new instance of FirstFragment if it isn't null, and add it to your view inside a container in your activity_main file. A container is a linear layout inside the view with the given amount of space that should be occupied by the fragment. In the case of a fullscreen fragment, the container is the root layout. You need only to specify an id to this layout. Once you create a new fragment, attach it by calling transaction.attach(); The final code block should be similar to this:
/** this example assumes that the fragment
* FirstFragment will be attached to tab 1
* which is at position = 0, and SecondFragment
* will be attached to tab 2, which is at
* position = 1. Also, the root layout of
* activity_main.xml has the id attribute of
* fragment_container
*/
FirstFragment firstFragment;
SecondFragment secondFragment;
#Override
public void onTabSelected(Tab tab, FragmentTransaction transaction) {
switch (tab.getPosition()) {
case 0:
if (firstFragment == null) {
firstFragment = new FirstFragment();
transaction.add(R.id.fragment_container,
firstFragment, "FIRST");
} else {
transaction.attach(firstFragment);
}
break;
case 1:
if (secondFragment == null) {
secondFragment = new SecondFragment();
transaction.add(R.id.fragment_container, secondFragment, "SECOND");
} else {
transaction.attach(secondFragment);
}
break;
}
}
I just started with fragment design for HoneyComb. I created two fragments. When i click a button in the left side fragment, a new fragment is created in right side. Meanwhile when i click a button in the right fragment(ie. DetialsFragment in my code below should be replaced by another fragment.
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<fragment class="com.fragment.example.Titles"
android:id="#+id/titles" android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
<FrameLayout android:id="#+id/details" android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
</LinearLayout>
FragmentExample.java
public class FragmentExample extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Titles.java
public class Titles extends Fragment {
public FragmentTransaction ft;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.main1, null);
Button button1 = (Button)v.findViewById(R.id.button1);
button1.setText("santhosh");
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != 1) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(1);
// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
ft
= getFragmentManager().beginTransaction();
ft.add(R.id.details, details, "detail");
ft.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
}
});
return v;
}
}
DetailsFragment.java
public class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
Titles title = new Titles();
String[] titles = {"Title1", "Title2", "Title3", "Title4"};
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
// Currently in a layout without a container, so no
// reason to create our view.
return null;
}
Button button = new Button(getActivity());
button.setText("Next");
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
return button;
}
}
Then provided your button is showing and the click event is being fired you can call the following in your click event:
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, new NewFragmentToReplace(), "NewFragmentTag");
ft.commit();
and if you want to go back to the DetailsFragment on clicking back ensure you add the above transaction to the back stack, i.e.
ft.addToBackStack(null);
Or am I missing something? Alternatively some people suggest that your activity gets the click event for the button and it has responsibility for replacing the fragments in your details pane.
Latest Stuff
Okay. So this is a very old question and has great answers from that time. But a lot has changed since then.
Now, in 2020, if you are working with Kotlin and want to change the fragment then you can do the following.
Add Kotlin extension for Fragments to your project.
In your app level build.gradle file add the following,
dependencies {
def fragment_version = "1.2.5"
// Kotlin
implementation "androidx.fragment:fragment-ktx:$fragment_version"
// Testing Fragments in Isolation
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}
Then simple code to replace the fragment,
In your activity
supportFragmentManager.commit {
replace(R.id.frame_layout, YourFragment.newInstance(), "Your_TAG")
addToBackStack(null)
}
References
Check latest version of Fragment extension
More on Fragments
You can try below code. it’s very easy method for push new fragment from old fragment.
private int mContainerId;
private FragmentTransaction fragmentTransaction;
private FragmentManager fragmentManager;
private final static String TAG = "DashBoardActivity";
public void replaceFragment(Fragment fragment, String TAG) {
try {
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(mContainerId, fragment, tag);
fragmentTransaction.addToBackStack(tag);
fragmentTransaction.commitAllowingStateLoss();
} catch (Exception e) {
// TODO: handle exception
}
}
Use android.support.v4.app for FragmentManager & FragmentTransaction in your code, it has worked for me.
DetailsFragment detailsFragment = new DetailsFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.details,detailsFragment);
fragmentTransaction.commit();
If you have a handle to an existing fragment you can just replace it with the fragment's ID.
Example in Kotlin:
fun aTestFuction() {
val existingFragment = MyExistingFragment() //Get it from somewhere, this is a dirty example
val newFragment = MyNewFragment()
replaceFragment(existingFragment, newFragment, "myTag")
}
fun replaceFragment(existing: Fragment, new: Fragment, tag: String? = null) {
supportFragmentManager.beginTransaction().replace(existing.id, new, tag).commit()
}
Updated Answer (Working for Overlap problem as well)
#aniket-thakur(https://stackoverflow.com/users/2396539/aniket-thakur) gave correct answer. Thank you for that!
But, getFragmentManager() is deprecated, so following code did work for me.
final FragmentTransaction ft = getParentFragmentManager().beginTransaction();
ft.replace(R.id.nav_host_fragment, new GalleryFragment(), "NewFragmentTag");
ft.addToBackStack(null);
ft.commit();
it's very simple how to replace with Fragment.
DataFromDb changeActivity = new DataFromDb();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.changeFrg, changeActivity);
transaction.commit();