I am developing application which contains 2 fragments and i want to show hide according to my need. Following code has simple example of my problem.
This simple Fragmentactivity contains 1 button and one listfragment.
This simple example works flawless. but i am not satisfied with show hide fragment. If you remove layout.setVisibility(View.GONE); from the code then ft.hide(f); will not hide fragment. In fact we are not hiding fragment we are hiding container.
My Question is, IS this a way to show hide fragments? If not then please explain with tested example How to hide and show Fragments because lots of people are facing this problem.
public class MainActivity extends FragmentActivity implements OnClickListener {
Fragment1 f;
Button b;
LinearLayout layout;
Fragment myf;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.button1);
layout = (LinearLayout) findViewById(R.id.ll);
f = new Fragment1();
}
#Override
public void onClick(View v) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
if (f.isHidden()) {
ft.show(f);
layout.setVisibility(View.VISIBLE);
b.setText("Hide");
} else {
ft.hide(f);
b.setText("Show");
layout.setVisibility(View.GONE);
}
ft.commit();
// TODO Auto-generated method stub
}
Don't mess with the visibility flags of the container - FragmentTransaction.hide/show does that internally for you.
So the correct way to do this is:
FragmentManager fm = getFragmentManager();
fm.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.show(somefrag)
.commit();
OR if you are using android.support.v4.app.Fragment
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.show(somefrag)
.commit();
In addittion, you can do in a Fragment (for example when getting server data failed):
getView().setVisibility(View.GONE);
Hi you do it by using this approach, all fragments will remain in the container once added initially and then we are simply revealing the desired fragment and hiding the others within the container.
// Within an activity
private FragmentA fragmentA;
private FragmentB fragmentB;
private FragmentC fragmentC;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
fragmentA = FragmentA.newInstance("foo");
fragmentB = FragmentB.newInstance("bar");
fragmentC = FragmentC.newInstance("baz");
}
}
// Replace the switch method
protected void displayFragmentA() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (fragmentA.isAdded()) { // if the fragment is already in container
ft.show(fragmentA);
} else { // fragment needs to be added to frame container
ft.add(R.id.flContainer, fragmentA, "A");
}
// Hide fragment B
if (fragmentB.isAdded()) { ft.hide(fragmentB); }
// Hide fragment C
if (fragmentC.isAdded()) { ft.hide(fragmentC); }
// Commit changes
ft.commit();
}
Please see https://github.com/codepath/android_guides/wiki/Creating-and-Using-Fragments for more info. I hope I get to help anyone. Even if it this is an old question.
public void showHideFragment(final Fragment fragment){
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.animator.fade_in,
android.R.animator.fade_out);
if (fragment.isHidden()) {
ft.show(fragment);
Log.d("hidden","Show");
} else {
ft.hide(fragment);
Log.d("Shown","Hide");
}
ft.commit();
}
Try this:
MapFragment mapFragment = (MapFragment)getFragmentManager().findFragmentById(R.id.mapview);
mapFragment.getView().setVisibility(View.GONE);
I may be way way too late but it could help someone in the future.
This answer is a modification to mangu23 answer
I only added a for loop to avoid repetition and to easily add more fragments without boilerplate code.
We first need a list of the fragments that should be displayed
public class MainActivity extends AppCompatActivity{
//...
List<Fragment> fragmentList = new ArrayList<>();
}
Then we need to fill it with our fragments
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
HomeFragment homeFragment = new HomeFragment();
MessagesFragment messagesFragment = new MessagesFragment();
UserFragment userFragment = new UserFragment();
FavoriteFragment favoriteFragment = new FavoriteFragment();
MapFragment mapFragment = new MapFragment();
fragmentList.add(homeFragment);
fragmentList.add(messagesFragment);
fragmentList.add(userFragment);
fragmentList.add(favoriteFragment);
fragmentList.add(mapFragment);
}
And we need a way to know which fragment were selected from the list, so we need getFragmentIndex function
private int getFragmentIndex(Fragment fragment) {
int index = -1;
for (int i = 0; i < fragmentList.size(); i++) {
if (fragment.hashCode() == fragmentList.get(i).hashCode()){
return i;
}
}
return index;
}
And finally, the displayFragment method will like this:
private void displayFragment(Fragment fragment) {
int index = getFragmentIndex(fragment);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (fragment.isAdded()) { // if the fragment is already in container
transaction.show(fragment);
} else { // fragment needs to be added to frame container
transaction.add(R.id.placeholder, fragment);
}
// hiding the other fragments
for (int i = 0; i < fragmentList.size(); i++) {
if (fragmentList.get(i).isAdded() && i != index) {
transaction.hide(fragmentList.get(i));
}
}
transaction.commit();
}
In this way, we can call displayFragment(homeFragment) for example.
This will automatically show the HomeFragment and hide any other fragment in the list.
This solution allows you to append more fragments to the fragmentList without having to repeat the if statements in the old displayFragment version.
I hope someone will find this useful.
From my code, comparing to above solution, the simplest way is to define a layout which contains the fragment, then you could hide or unhide the fragment by controlling the layout attribute which is align with the general way of view. No additional code needed in this case and the additional deployment attributes of the fragment could be moved to the outer layout.
<LinearLayout style="#style/StHorizontalLinearView"
>
<fragment
android:layout_width="match_parent"
android:layout_height="390dp"
android:layout_alignParentTop="true"
/>
</LinearLayout>
final Fragment fragment1 = new fragment1();
final Fragment fragment2 = new fragment2();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
In onCreate, after setContentView, i hid two fragments and committed them to the fragment manager, but i didn't hide the first fragment that will serve as home.
fm.beginTransaction().add(R.id.main_container, fragment2, "2").hide(fragment2).commit();
fm.beginTransaction().add(R.id.main_container,fragment1, "1").commit();
#Override
public void onClick(View v) {
Fragment another = fragment1;
if(active==fragment1){
another = fragment2;
}
fm.beginTransaction().hide(active).show(another).commit();
active = another;
}
Ref : https://medium.com/#oluwabukunmi.aluko/bottom-navigation-view-with-fragments-a074bfd08711
This worked for me
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if(tag.equalsIgnoreCase("dashboard")){
DashboardFragment dashboardFragment = (DashboardFragment)
fragmentManager.findFragmentByTag("dashboard");
if(dashboardFragment!=null) ft.show(dashboardFragment);
ShowcaseFragment showcaseFragment = (ShowcaseFragment)
fragmentManager.findFragmentByTag("showcase");
if(showcaseFragment!=null) ft.hide(showcaseFragment);
} else if(tag.equalsIgnoreCase("showcase")){
DashboardFragment dashboardFragment = (DashboardFragment)
fragmentManager.findFragmentByTag("dashboard");
if(dashboardFragment!=null) ft.hide(dashboardFragment);
ShowcaseFragment showcaseFragment = (ShowcaseFragment)
fragmentManager.findFragmentByTag("showcase");
if(showcaseFragment!=null) ft.show(showcaseFragment);
}
ft.commit();
the answers here are correct and i liked #Jyo the Whiff idea of a show and hide fragment implementation except the way he has it currently would hide the fragment on the first run so i added a slight change in that i added the isAdded check and show the fragment if its not already
public void showHideCardPreview(int id) {
FragmentManager fm = getSupportFragmentManager();
Bundle b = new Bundle();
b.putInt(Constants.CARD, id);
cardPreviewFragment.setArguments(b);
FragmentTransaction ft = fm.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
if (!cardPreviewFragment.isAdded()){
ft.add(R.id.full_screen_container, cardPreviewFragment);
ft.show(cardPreviewFragment);
} else {
if (cardPreviewFragment.isHidden()) {
Log.d(TAG,"++++++++++++++++++++ show");
ft.show(cardPreviewFragment);
} else {
Log.d(TAG,"++++++++++++++++++++ hide");
ft.hide(cardPreviewFragment);
}
}
ft.commit();
}
Related
I have a fragment inside a group activity and I want to replace it with another fragment:
FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
SectionDescriptionFragment bdf = new SectionDescriptionFragment();
ft.replace(R.id.book_description_fragment, bdf);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
It works fine when it is done as a seperate project without using activity group, every thing works fine in log cat as control goes inside getview(), but no view is visible, not even any exception arises, I want the book detail fragment to be replaced by section detail fragment.
Xml of book detail fragment has id book_description_fragment and xml for section description fragment has id section_description_fragment.
The above code is in onClick method of an item, I want that when user taps on an item in horizontal scroll view, then the fragment changes.
Fragments that are hard coded in XML, cannot be replaced. If you need to replace a fragment with another, you should have added them dynamically, first of all.
Note: R.id.fragment_container is a layout or container of your choice in the activity you are bringing the fragment to.
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().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();
Please see this Question
You can only replace a "dynamically added fragment".
So, if you want to add a dynamic fragment, see this example.
I've made a gist with THE perfect method to manage fragment replacement and lifecycle.
It only replace the current fragment by a new one, if it's not the same and if it's not in backstack (in this case it will pop it).
It contain several option as if you want the fragment to be saved in backstack.
=> See Gist here
Using this and a single Activity, you may want to add this to your activity:
#Override
public void onBackPressed() {
int fragments = getSupportFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
return;
}
super.onBackPressed();
}
Use the below code in android.support.v4
FragmentTransaction ft1 = getFragmentManager().beginTransaction();
WebViewFragment w1 = new WebViewFragment();
w1.init(linkData.getLink());
ft1.addToBackStack(linkData.getName());
ft1.replace(R.id.listFragment, w1);
ft1.commit();
Use ViewPager. It's work for me.
final ViewPager viewPager = (ViewPager) getActivity().findViewById(R.id.vp_pager);
button = (Button)result.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewPager.setCurrentItem(1);
}
});
hope you are doing well.when I started work with Android Fragments then I was also having the same problem then I read about
1- How to switch fragment with other.
2- How to add fragment if Fragment container does not have any fragment.
then after some R&D, I created a function which helps me in many Projects till now and I am still using this simple function.
public void switchFragment(BaseFragment baseFragment) {
try {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
if (getSupportFragmentManager().findFragmentById(R.id.home_frame) == null) {
ft.add(R.id.home_frame, baseFragment);
} else {
ft.replace(R.id.home_frame, baseFragment);
}
ft.addToBackStack(null);
ft.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
enjoy your code time :)
you can use simple code its work for transaction
Fragment newFragment = new MainCategoryFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame_NavButtom, newFragment);
ft.commit();
You Can Use This code
((AppCompatActivity) getActivity()).getSupportFragmentManager().beginTransaction().replace(R.id.YourFrameLayout, new YourFragment()).commit();
or You Can This Use Code
YourFragment fragments=(YourFragment) getSupportFragmentManager().findFragmentById(R.id.FrameLayout);
if (fragments==null) {
getSupportFragmentManager().beginTransaction().replace(R.id.FrameLayout, new Fragment_News()).commit();
}
I change fragment dynamically in single line code
It is work in any SDK version and androidx
I use navigation as BottomNavigationView
BottomNavigationView btn_nav;
FragmentFirst fragmentFirst;
FragmentSecond fragmentSecond;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
fragmentFirst = new FragmentFirst();
fragmentSecond = new FragmentSecond ();
changeFragment(fragmentFirst); // at first time load the fragmentFirst
btn_nav = findViewById(R.id.bottomNav);
btn_nav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch(menuItem.getItemId()){
case R.id.menu_first_frag:
changeFragment(fragmentFirst); // change fragmentFirst
break;
case R.id.menu_second_frag:
changeFragment(fragmentSecond); // change fragmentSecond
break;
default:
Toast.makeText(SearchActivity.this, "Click on wrong bottom SORRY!", Toast.LENGTH_SHORT).show();
}
return true;
}
});
}
public void changeFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout_changer, fragment).commit();
}
In kotlin you can do:
// instantiate the new fragment
val fragment: Fragment = ExampleFragment()
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.book_description_fragment, fragment)
transaction.addToBackStack("transaction_name")
// Commit the transaction
transaction.commit()
This will work if you're trying to change the fragment from another fragment.
Objects.requireNonNull(getActivity()).getSupportFragmentManager()
.beginTransaction()
.replace(R.id.home_fragment_container,new NewFragment())
NOTE As stated in the above answers, You need to have dynamic fragments.
You can use fragment-ktx
// If you are in fragmet
childFragmentManager.beginTransaction()
// or if you are in activiry
supportFragmentManager.beginTransaction()
// Create and commit a new transaction
supportFragmentManager.commit {
setReorderingAllowed(true)
// Replace whatever is in the fragment_container view with this fragment
replace<ExampleFragment>(R.id.fragment_container)
}
To replace a fragment with another one do this, Note that R.id.fragment comes from the id that you give to the first tag of the fragment in the XML.
barAudioPlaying.setOnClickListener(view -> {
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment,new HomeFragment())
.commit();
I show animation when user navigates away from fragment. For that I am using setCustomAndimations of support package.
"popEnter" and "popExit" work fine, but they are lost after activity gets rotated,
i.e. after rotation popping fragment happens without the animation.
Fragment creation in activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState == null) { // activity started for the first time, no fragment attached yet
fragment = MyFragment.newInstance(params);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(0, 0, // enter animations, not important here
// when popping fragment -> these are lost on rotation
R.anim.slide_in_right, R.anim.slide_out_right);
ft.add(R.id.content, fragment, MY_TAG).addToBackStack(null).commit();
}
}
Is there way / workaround to keep animating "popping out" of fragment after rotation ?
I found a temporarily solution for this problem here (answer #3)
fix this by adding:
android:configChanges="orientation|screenSize"
to your FragmentActivity in the manifest.
There are of course problems, when you i.e. inflate different layouts in your onCreateView, depending on the screen size. So thats also not a final answer.
Edit: you can create your own backstack:
public final class MBackStack {
public static Stack<Fragment> fragStack = new Stack<>();
private MBackStack(){}
public static void addFragment(Fragment frag){
fragStack.push(frag);
}
public static Fragment getFragment(){
if (fragStack.isEmpty()) {
return null;
}
fragStack.pop();
Fragment fragment = fragStack.peek();
return fragment;
}
public static int getStackSize(){
return fragStack.size();
}
public static void clearStack(){
while (fragStack.size()!=0){
fragStack.pop();
}
}
}
Now instead of
ft.addToBackStack(null);
You can add:
YOURFRAGMENT yf = new YOURFRAGMENT();
MBackStack.addFragment(yf);
ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, dts);
ft.commit();
And in your main activity you can override your onbackpressed:
#Override
public void onBackPressed() {
if(MBackStack.getStackSize()>1){
ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.in_left, R.anim.out_right);
ft.replace(R.id.content_frame, MBackStack.getFragment());
ft.commit();
}else{
finish();
overridePendingTransition(R.anim.no_animation, R.anim.slide_bottom_out);
}
}
I have tried it, and it works fine.
I am working on the following tutorial, it has problems : it recreates the fragments after each screen rotation.
I fixed it concerning the TitlesFragment class by adding if(savedInstanceState == null) in QuoteViewerActivity:
mFragmentManager = getFragmentManager();
//ADDED THIS CONDITION
if(savedInstanceState == null){
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.title_fragment_container, mTitlesFragment);
fragmentTransaction.commit();
}
it fixed it for Fragment TitlesFragment however for Fragment QuoteFragment it is still recreating it on each screen orientation change because in this tutorial that fragment is created in an onclick event:
#Override
public void onListSelection(int index) {
if (!mDetailsFragment.isAdded()) {
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.quote_fragment_container, mDetailsFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
mFragmentManager.executePendingTransactions();
}
if (mDetailsFragment.getShownIndex() != index) {
mDetailsFragment.showIndex(index);
}
}
note that setRetainInstance(true) is set in both fragment's onCreate().
I tried to add this checking but it didn't fix it:
#Override
public void onListSelection(int index) {
//ADDED THE FOLLOWING TWO LINES
Fragment f = mFragmentManager.findFragmentById(R.id.quote_fragment_container);
if(f == null)
//===============================
if (!mDetailsFragment.isAdded()) {
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.quote_fragment_container, mDetailsFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
mFragmentManager.executePendingTransactions();
}
if (mDetailsFragment.getShownIndex() != index) {
mDetailsFragment.showIndex(index);
}
}
==> It recreates this Fragment each time I rotate the screen and duplicates existing menus (explained in this snapshot):
What am I doing wrong and what is the best practice to fix this? thanks!
This line won't find the fragment you're trying to find:
Fragment f = mFragmentManager.findFragmentById(R.id.quote_fragment_container);
You provided container (layout) id. This method can be used to find fragments that were inflated from XML layout.
If you want to manage fragments from code, use tag. Add a fragment using FragmentTransaction.add(int containerViewId, Fragment fragment, String tag). Providing a tag you can later find that fragment using FragmentManager.findFragmentByTag(String tag). It's a good idea to make tag some kind of static final String constant, making automatic refactoring a breeze.
You may be also interested with method FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag) - it makes fragment replacement easier.
Solution:
In this specific tutorial the solution for this problem was solved by:
using onSaveInstanceState to store QuoteFragment state to its containing activity
Getting/handling the QuoteFragment by checking if it is found in the savedInstanceState
Here is what I added/changed in the code:
.....
private QuoteFragment mDetailsFragment = new QuoteFragment();//REMOVED final attribute
......
//ADDED
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(mFragmentManager.findFragmentByTag(quote_fragment_tag)!=null)
getFragmentManager().putFragment(outState, QuoteFragment.class.getName(), mDetailsFragment);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TitleArray = getResources().getStringArray(R.array.Titles);
QuoteArray = getResources().getStringArray(R.array.Quotes);
setContentView(R.layout.main);
mFragmentManager = getFragmentManager();
// ADDED
if(savedInstanceState == null){
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.title_fragment_container, mTitlesFragment);
fragmentTransaction.commit();
}
else{//ADDED
mDetailsFragment = (QuoteFragment) getFragmentManager()
.getFragment(savedInstanceState, QuoteFragment.class.getName());
if(mDetailsFragment == null){
mDetailsFragment = new QuoteFragment();
mFragmentManager.beginTransaction()
.add(R.id.quote_fragment_container, mDetailsFragment,quote_fragment_tag)
.addToBackStack(null)
.commit();
mFragmentManager.executePendingTransactions();
}
}
}
Note: in my humble opinion for best practices concerning fragments and config changes on runtime check Google's official tutorial.
Another simple solution.Add
menu.clear()
before inflating the menu in onCreateOptionsMenu method inside the fragment
#Override
public void onCreateOptionsMenu(Menu menu,MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.menu_main, menu);
}
I am having trouble figuring out the proper way to navigate through fragments without a pager and i am having problems during Configuration changes for screen orientation. I am using Show/Hide on the fragments to make them visible and functional but i am wondering if i should instead be using Detach/Attach. I am also having problems adding things to the back stack and i think it is also due to the use of show/hide. Is it better to use Attach/detatch or is there a way to override what the back button does to make it show/hide the last/current fragment.
The Behavior:
I have a map fragment and a List fragment along with a few others. everything starts up correctly and works initially with orientation changes. When i navigate to the list view it populates correctly but upon orientation change the list gets redrawn without the Data in it. The map view also gets redrawn and is visible behind my pager title indicator.
If anyone could please point me in right direction for solving this that would be awesome. I am suspecting that is is caused by the way that i am showing and hiding the fragments.
Here is where i create the Fragments and add them to the fragment manager. I have also shown where i show/hide fragments.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_frags);
mapViewContainer = LayoutInflater.from(this)
.inflate(R.layout.map, null);
setupFragments();
showFragment(0);
}
public void setListData(String name) {
bName = name;
showFragment(1);
}
private void setupFragments() {
final FragmentManager fm = getSupportFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
mFragment1 = fm.findFragmentByTag("f1");
if (mFragment1 == null) {
mFragment1 = new MenuFragment();
ft.add(mFragment1, "f1");
ft.hide(mFragment1);
}
mMapFragment = (MapFragment) getSupportFragmentManager()
.findFragmentByTag(MapFragment.TAG);
if (mMapFragment == null) {
mMapFragment = MapFragment.newInstance(0);
ft.add(R.id.fragment_container, mMapFragment, MapFragment.TAG);
}
ft.hide(mMapFragment);
myListFragment = (ListFrag) getSupportFragmentManager()
.findFragmentByTag(ListFrag.TAG);
if (myListFragment == null) {
myListFragment = new ListFrag();
ft.add(R.id.fragment_container, myListFragment, ListFrag.TAG);
}
ft.hide(myListFragment);
frag = (frag) getSupportFragmentManager().findFragmentByTag(
frag.TAG);
if (frag == null) {
bacFrag = new frag();
ft.add(R.id.fragment_container, frag, frag.TAG);
}
ft.hide(bacFrag);
ft.commit();
}
public void showFragment(int fragIn) {
final FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
if (mVisible != null) {
if (mVisible == mListFragment) {
ft.remove(mListFragment);
} else {
ft.hide(mVisible);
}
}
switch (fragIn) {
case 0:
ft.show(mMapFragment);
ft.commit();
mVisible = mMapFragment;
break;
case 1:
mListFragment = (ListFragmentDisplay) getSupportFragmentManager()
.findFragmentByTag(ListFragmentDisplay.TAG);
Toast.makeText(this, "startListFrag", Toast.LENGTH_LONG).show();
if (mListFragment == null) {
mListFragment = new ListFragmentDisplay();
ft.add(R.id.fragment_container, mListFragment,
ListFragmentDisplay.TAG);
}
ft.show(mListFragment).commit();
mVisible = mListFragment;
break;
case 2:
ft.show(myfragment).commit();
mVisible = myfragment;
break;
case 3:
ft.show(frag).commit();
mVisible = frag;
break;
}
}
It's not your fault. The problem is that when the orientation changes all the Activity is Destroyed, even all the fragments added. So none of the data within it is retained.
It's not advised to use android:configChanges="orientation|keyboardHidden".
Rather, set for every fragment setRetainInstance(true) and it will work well with your current code.
If you want to have a better persistence (for example when the activity is temporarily destroyed for space issues) also remember to save the state of your fragments with onSaveInstanceState. setRetainInstance will work only when a configuration change is about to come.
In my main.xml I have
<FrameLayout
android:id="#+id/frameTitle"
android:padding="5dp"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:background="#drawable/title_bg">
<fragment
android:name="com.fragment.TitleFragment"
android:id="#+id/fragmentTag"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</FrameLayout>
And I'm setting fragment object like this
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new FragmentType1();
fragmentTransaction.replace(R.id.frameTitle, casinodetailFragment, "fragmentTag");
// fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
It is setting different types of Fragment objects (FragmentType2,FragmentType3,...) at different time. Now at some point of time I need to identify which object is currently there.
In short I need to do something like this:
Fragment currentFragment = //what is the way to get current fragment object in FrameLayout R.id.frameTitle
I tried the following
TitleFragment titleFragmentById = (TitleFragment) fragmentManager.findFragmentById(R.id.frameTitle);
and
TitleFragment titleFragmentByTag = (TitleFragment) fragmentManager.findFragmentByTag("fragmentTag");
But both the objects (titleFragmentById and titleFragmentByTag ) are null
Did I miss something?
I'm using Compatibility Package, r3 and developing for API level 7.
findFragmentById() and findFragmentByTag() will work if we have set fragment using fragmentTransaction.replace or fragmentTransaction.add, but will return null if we have set the object at xml (like what I have done in my main.xml). I think I'm missing something in my XML files.
Now at some point of time I need to identify which object is currently there
Call findFragmentById() on FragmentManager and determine which fragment is in your R.id.frameTitle container.
If you are using the androidx edition of Fragment — as you should in modern apps — , use getSupportFragmentManager() on your FragmentActivity/AppCompatActivity instead of getFragmentManager()
Try this,
Fragment currentFragment = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
this will give u the current fragment, then you may compare it to the fragment class and do your stuffs.
if (currentFragment instanceof NameOfYourFragmentClass) {
Log.v(TAG, "find the current fragment");
}
I think you can use onAttachFragment event may be useful to catch which fragment is active.
#Override
public void onAttachFragment(Fragment fragment) {
// TODO Auto-generated method stub
super.onAttachFragment(fragment);
Toast.makeText(getApplicationContext(), String.valueOf(fragment.getId()), Toast.LENGTH_SHORT).show();
}
I think you should do:
Fragment currentFragment = fragmentManager.findFragmentByTag("fragmentTag");
The reason is because you set the tag "fragmentTag" to the last fragment you have added (when you called replace).
You can get the list of the fragments and look to the last one.
FragmentManager fm = getSupportFragmentManager();
List<Fragment> fragments = fm.getFragments();
Fragment lastFragment = fragments.get(fragments.size() - 1);
But sometimes (when you navigate back) list size remains same but some of the last elements are null. So in the list I iterated to the last not null fragment and used it.
FragmentManager fm = getSupportFragmentManager();
if (fm != null) {
List<Fragment> fragments = fm.getFragments();
if (fragments != null) {
for(int i = fragments.size() - 1; i >= 0; i--){
Fragment fragment = fragments.get(i);
if(fragment != null) {
// found the current fragment
// if you want to check for specific fragment class
if(fragment instanceof YourFragmentClass) {
// do something
}
break;
}
}
}
}
This is the simplest solution and work for me.
1.) you add your fragment
ft.replace(R.id.container_layout, fragment_name, "fragment_tag").commit();
2.)
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentById(R.id.container_layout);
if(currentFragment.getTag().equals("fragment_tag"))
{
//Do something
}
else
{
//Do something
}
It might be late but I hope it helps someone else, also #CommonsWare has posted the correct answer.
FragmentManager fm = getSupportFragmentManager();
Fragment fragment_byID = fm.findFragmentById(R.id.fragment_id);
//OR
Fragment fragment_byTag = fm.findFragmentByTag("fragment_tag");
Maybe the simplest way is:
public MyFragment getVisibleFragment(){
FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
List<Fragment> fragments = fragmentManager.getFragments();
for(Fragment fragment : fragments){
if(fragment != null && fragment.getUserVisibleHint())
return (MyFragment)fragment;
}
return null;
}
It worked for me
You can create field in your parent Activity Class:
public class MainActivity extends AppCompatActivity {
public Fragment fr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
And then inside each fragment class:
public class SomeFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
((MainActivity) getActivity()).fr = this;
}
Your 'fr' field is current fragment Object
It's working also with popBackStack()
I know it's been a while, but I'll this here in case it helps someone out.
The right answer by far is (and the selected one) the one from CommonsWare. I was having the same problem as posted, the following
MyFragmentClass fragmentList =
(MyFragmentClass) getSupportFragmentManager().findFragmentById(R.id.fragementID);
kept on returning null. My mistake was really silly, in my xml file:
<fragment
android:tag="#+id/fragementID"
android:name="com.sf.lidgit_android.content.MyFragmentClass"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
The mistake was that I had android:tag INSTEAD OF android:id.
Do a check (which fragment in the activity container) in the onStart method;
#Override
protected void onStart() {
super.onStart();
Fragment fragmentCurrent = getSupportFragmentManager.findFragmentById(R.id.constraintLayout___activity_main___container);
}
Some check:
if (fragmentCurrent instanceof MenuFragment)
#Hammer response worked for me, im using to control a floating action button
final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
android.app.Fragment currentFragment = getFragmentManager().findFragmentById(R.id.content_frame);
Log.d("VIE",String.valueOf(currentFragment));
if (currentFragment instanceof PerfilFragment) {
PerfilEdit(view, fab);
}
}
});
If you are extending from AbstractActivity, you could use the getFragments() method:
for (Fragment f : getFragments()) {
if (f instanceof YourClass) {
// do stuff here
}
}
If you are defining the fragment in the activity's XML layour then in the Activity make sure you call setContentView() before calling findFragmentById().
If you are using the BackStack...and ONLY if you are using the back stack, then try this:
rivate Fragment returnToPreviousFragment() {
FragmentManager fm = getSupportFragmentManager();
Fragment topFrag = null;
int idx = fm.getBackStackEntryCount();
if (idx > 1) {
BackStackEntry entry = fm.getBackStackEntryAt(idx - 2);
topFrag = fm.findFragmentByTag(entry.getName());
}
fm.popBackStack();
return topFrag;
}
This will give you the current fragment class name -->
String fr_name = getSupportFragmentManager().findFragmentById(R.id.fragment_container).getClass().getSimpleName();
you can check which fragment is currently loaded by this
supportFragmentManager.addOnBackStackChangedListener {
val myFragment = supportFragmentManager.fragments.last()
if (null != myFragment && myFragment is HomeFragment) {
//HomeFragment is visible or currently loaded
} else {
//your code
}
}
I use the following function in Kotlin:
supportFragmentManager.fragments.run {
getOrNull(size - 1)?.let { currentFragment ->
...
}
}
I recently worked on an activity involving multiple fragments so thought to share the method I used here:
Firstly, I declared a function getCurrentFragment() which returned me, yeah you guessed it, the current fragment, lol.
private fun getCurrentFragment(): Fragment? {
return supportFragmentManager.findFragmentById(R.id.fragmentContainerView)
}
Then I override the onBackPressed function in the activity to define the navigation within fragments. Suppose, I wanted to show fragment 2 if user is in fragment 3 and presses back so I did something like this to achieve this
override fun onBackPressed() {
if (getCurrentFragment() is Fragment3) {
showFragment2()
} else {
super.onBackPressed()
}
}
And in showFragment2() I did something like this:
private fun showFragment2() {
val fragment = Fragment2.newInstance()
supportFragmentManager.commit {
replace(R.id.FragmentContainerView, fragment, "Add a tag here")
}
}
I think this should give better idea to people looking on how to navigate through fragments within an activity.