Changing Fragment - android

I recently modified my ActionBar as to have two tabs, corresponding to two Fragments respectively.
Let's say my first tab is the Main Page, the second my About Page.
The About Page is static.
The Main Page changes. Let's say, for question's sake, that the Main Page has this single button in the center of the screen. I want it in such a way that when the user clicks the button, the page changes to another screen with text. This is easily done with Activities using Intent. I don't know how to do this with Fragments.
In sum, what is the best practice switching Fragments inside a tab?

Consider using fragment's method getChildFragmentManager().
So your way to go.
In you first tab
Create nested fragment whitch will display button.
MainPage.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
/>
</LinearLayout>
class MainPage extends Fragment(){
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, new ButtonFragment(), ButtonFragment.class.getName());
ft.commit();
((Button)getActivity().findViewById(R.id.your_button)).setOnClickListener(new OnClickListener(){
public void onClick(View v){
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, new TextFragment(), TextFragment.class.getName());
ft.addToBackStack(TextFragment.class.getName());
ft.commit();
}
})
}
public boolean onBackPressed(){
FragmentManager mn = getChildFragmentManager();
if(mn.getBackStackEntryCount()>0)
mn.popBackStack(man.getBackStackEntryAt(0).getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
class ButtonFragment extends Fragment(){
.....
public void onCreateView(Bundle savedinstance){
//inflate you view with button here
}

Related

When navigating from one fragment to another, the second fragment overlaps

On the click of a button I want to navigate from one fragment to another. The problem is that when I press the button the second fragment overlaps the other.
I searched for some answers but it doesn't seem to word in my case. I tried adding a background color but it still overlaps.
So after I click the button the following thing happens:
Here are my codes:
I gave the first fragment an ID:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment"
android:background="#FFF">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="1dip"
app:layout_constraintBottom_toTopOf="parent"
android:background="#FFF"/>
The ID of the button is: nextFragment
The code inside the class of the first fragment is:
nextFragment = v.findViewById(R.id.nextFragment);
nextFragment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Fragment fragment = new NotificationsFragment();
FragmentManager fragmentManager = getParentFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
}
});
Hope i gave enough information, if not don't hesitate to ask for more! Thanks in advance.
The problem is that you are using fragment_container as the first fragment instead of the container for your first fragment.
In your MainActivity you have to load your first fragment inside that container. Not use it as a fragment.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
Fragment firstFragment = new YourFirstFragment();
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, firstFragment);
transaction.commit();
}
}
After that, in your first fragment, when you will replace the fragment it will work great.
So the solution was simple.. I gave an Id to a framelayout inside the first fragment instead of to the root layout.
Now the next thing is that the tab on the bottom also has to change when the button is pressed.

Android - Call a fragment inside tab

I try to create an application that has two pages. First page is a tabbed page and second page is a detail page.
I create a tapped page using this guide. I have a mainactivity that contains view pager and 3 tabs(Tab1, Tab2, Tab3). Tab3 contains a button to navigate detail page. Each tab has own .java(extends Fragment) and .xml file. I edit fragmentThree.xml layout :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fragmentThree"]>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/goToDetail"
android:text="GO TO DETAIL" />
I create a new fragment for detail page. I set onclick method inside of Tab3.java;
goToDetail.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.mainActivity, new Detail());
transaction.commit();
}
});
When I press the button, it doesn't do anything. I don't replace the fragment.
Use you viewpager id instead of main layout id, where you set the tab layout fragment.
transaction.replace(R.id.viewpager, new Detail());
use Frame layout in Main Activity
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/parent">
In clicklistiner :-
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.parent, new Detail());
transaction.commit();

Fragment not added to backstack

I'm having trouble with getting Fragments and the backstack to work.
I've got a layout with a FrameLayout for holding various fragments and another fragment:
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/filterableListContainer"
android:layout_weight="50">
</FrameLayout>
<fragment class="com.facetoe.remotempd.fragments.PlayerBarFragment"
android:id="#+id/playerBarFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:layout="#layout/player_bar"/>
</LinearLayout>
When I start the Activity that uses this layout I add the fragment to the FrameLayout like so:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
if (findViewById(R.id.filterableListContainer) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
ArtistListFragment listFragment = new ArtistListFragment();
// Add the fragment to the 'fragment_container' FrameLayout
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.filterableListContainer, listFragment);
ft.addToBackStack(null);
ft.commit();
} else {
Log.e(TAG, "Couldn't find filterableListFragment");
}
}
When the user clicks an item, I attempt to replace the fragment with this code:
ArtistAlbumsListFragment fragment = new ArtistAlbumsListFragment(getActivity(), albums);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.filterableListContainer, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
However when I press the back button I get returned to the home screen. Can anyone tell me where I'm going wrong?
Ok I fixed it. When I created the Activity in Intellij it created a subclass of ActionBarActivity. Removing ActionBarActivity and replacing it with Activity made the fragments transitions work as expected.
Dont add ft.addToBackStack(null) this statement.
ArtistAlbumsListFragment fragment = new ArtistAlbumsListFragment(getActivity(), albums);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.filterableListContainer, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();

How can I identify the current fragment of my activity while using tabs and fragment container?

I want to call an fragment method from my activity, describe like in this SO-question: FindByID
TestFragment testFrag = (TestFragment) getFragmentManager().getFragmentById(R.id.testfragment);
if(testFrag != null && testFrag.isAdded())
testFrag.testMethod("Test");
As seen they identify the fragment by ID which is set in the xml. As I only have a fragment container none of my fragment layouts have a ID.
So my seconds thought was using the function getFragmentByTag `like in Tags
fragmentTransaction.replace(R.id.frameTitle, casinodetailFragment, "fragmentTag");
but as I use an action bar with tabs I don't have any tags:
My activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragmentcontainer);
// ActionBar gets initiated
ActionBar actionbar = getActionBar();
actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Define Tabs
ActionBar.Tab BasicInfoTab = actionbar.newTab().setText(
R.string.tab_BaseInfo);
..
// Define Fragments
PlantBasicInfoFragment BasicInfoFragment = new PlantBasicInfoFragment();
..
// Set TabListeners
BasicInfoTab.setTabListener(new TabListener(BasicInfoFragment));
..
// Add tabs to Actionbar
actionbar.addTab(BasicInfoTab);
..
// Icon clickable
actionbar.setDisplayHomeAsUpEnabled(true);
}
and its layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<LinearLayout
android:orientation="horizontal"
android:id="#+id/LabeledObjectHeaderInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<!-- ... -->
</LinearLayout >
<!-- fragment container -->
<LinearLayout
android:orientation="horizontal"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</LinearLayout>
</LinearLayout>
One of my fragments:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:id="#+id/table">
<TableRow>
<!-- ... -->
</TableRow>
<!-- ... -->
</TableLayout>
and finally my tab listener
public class TabListener implements ActionBar.TabListener {
public Fragment fragment;
public TabListener(Fragment fragment) {
this.fragment = fragment;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#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);
}
}
So how can I identify my current fragment?
Thanks in advance
P.S. The whole tab switching works perfectly, but now I want to build an addional feature inside the activity!
Add a tag while creating tabs.
ActionBar.Tab BasicInfoTab = actionbar.newTab().setText(R.string.tab_BaseInfo);
BasicInfoTab.setTag("tab1");
And in the listener class, retrieve the tag upon event.
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
String tabId = tab.getTag().toString();
}
This way you get the current tag. To identify the current fragment, you can keep a stack of fragments and pick the right one on tab change.
Edit
The tabId, aforementioned, identifies which tab is which. In order to set a fragment id/tag, there are many ways depending on your needs. One method is to replace your actual fragment layout with an intermediate layout.
For instance, A be the fragment you want to add to fragment container. Create another fragment class called IntermediateFragment with the following layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:baselineAligned="false">
<fragment
android:id="#+id/fragmentId"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="classA" />
</LinearLayout>
Now assign the layout you mentioned in the post (containing table) as a new one and add it to fragment class A. Now add Intermediate fragment to container which in turn pulls fragment A. Identify fragment A by id/tag added in the layout.
Hope it makes some sense!
Finally I got my solution by changing the TabListener, so I can add the fragment with an tag and then use the findFragmentByTag() function.
So my TabListener now looks like this (only constructor and onTabSelected changed)
public TabListener(Fragment fragment, String tag) {
this.fragment = fragment;
this.fragmentTag = tag;
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.replace(R.id.fragment_container, fragment, fragmentTag);
}
With this I only need to add a string (as tag) when adding the TabListener to my fragments and don't have to do further changes.

Dynamically add fragment into fragment

I haven't been able to find a way how to dynamically add fragment into existing dynamically added fragment. Do you know, if it is possible?
I am generating fragments this way:
FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
if(null == fragMgr.findFragmentByTag(FRAG1_TAG)) {
xact.add(10101010, new DateTime(), FRAG1_TAG);
}
if(null == fragMgr.findFragmentByTag(FRAG4_TAG)) {
xact.add(7777, new loginForm(), FRAG4_TAG);
}
xact.commit();
How to add into FRAG4_TAG fragment another one?
Edit2:
I hard coded it's id to be able to work with it in future (where ll is my linearLayout in XML):
FrameLayout frml4 = (FrameLayout)inflater.inflate(R.layout.frame,null);
frml4.setId(7777);
frml4.setBackgroundColor(Color.YELLOW);
ll.addView(frml4);
I assume the problem that you are running into is that there is not an inflated view to add the fragment to because the original fragment, FRAG4_TAG, has not been inflated before you are trying to add it.
You can pass enough information to FRAG4_TAG in the Arguments to let it know that it should create and add a fragment (or what all fragments you need it to have) to itself during it's onCreateView, after the view has been inflated...
The layout for the activity...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="MyActivity"/>
<LinearLayout
android:orientation="vertical"
android:id="#+id/main_frag_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
The Activity...
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragOne = new MyFragment();
Bundle arguments = new Bundle();
arguments.putBoolean("shouldYouCreateAChildFragment", true);
fragOne.setArguments(arguments);
ft.add(R.id.main_frag_container, fragOne);
ft.commit();
}
}
The layout for the fragment...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="20dp">
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Some fragment"/>
<LinearLayout
android:orientation="vertical"
android:id="#+id/frag_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
The fragment...
public class MyFragment extends Fragment {
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.frag_layout, container, false);
boolean shouldCreateChild = getArguments().getBoolean("shouldYouCreateAChildFragment");
if (shouldCreateChild) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragTwo = new MyFragment();
Bundle arguments = new Bundle();
arguments.putBoolean("shouldYouCreateAChildFragment", false);
fragTwo.setArguments(arguments);
ft.add(R.id.frag_container, fragTwo);
ft.commit();
}
return layout;
}
}
This example covers the case where you need to dynamically add fragments to a fragment that HAS NOT already been inflated and added to the hierarchy. Adding a fragment to a fragment that HAS already been inflated and added to the hierarchy is as simple as just specifying the target fragments container that you want to add to by ID like you would normally.
As the documentation states "A fragment must always be embedded in an activity".
So when you add a "sub-fragment" it will always belong to the activity even if you add it within your fragment class. For example if you later decide to remove the containing fragment the sub fragments won't be automatically removed.
When I had to do the same I had to store in a vector the sub fragments and manually remove them in the onDestroy methods of my container fragment.
I think that fragments are not thought to be used like this
You cannot insert Fragments into other Fragments. (At least, not yet)
You can however replace Fragments with other Fragments with FragmentTransaction.replace(containerViewId, Fragment).
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.linear1, new activity()).commit();
}

Categories

Resources