fragment placehoder in layout - android

Suppose I have several fragments:
public class FirstFragment extends Fragment { ... }
public class SecondFragment extends Fragment { ... }
public class ThirdFragment extends Fragment { ... }
I have also a main activity, its content is (main.xml):
<LinearLayout ...>
<!-- How to have a fragment placehold without specify which fragment show here? -->
<fragment>
</LinearLayout>
My question is, in above layout file, how can I define a fragment placeholder without specify which fragment show here, and then in My Activity java code, inflate a proper fragment to the placeholder ?
Is it possible and how to do it?

It is possible.
In your main.xml, define a place holder for the fragment, let's call it "fragment_placeholder":
<LinearLayout ...>
<FrameLayout android:id="#+id/fragment_placeholder" android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
</LinearLayout>
In your activity, whenever you want to load your fragment:
YourFragment fragment = new YourFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_placeholder, fragment);
ft.commit();

You can also use FragmentContainerView. From the documentation:
FragmentContainerView is a customized Layout designed specifically for
Fragments. It extends FrameLayout, so it can reliably handle Fragment
Transactions, and it also has additional features to coordinate with
fragment behavior.
Example (also from the docs):
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.fragment.app.FragmentContainerView>

Related

Add nested fragments in Parent fragment from activity

I have an SchoolActivity that has two buttons:
-Primary (adds the PrimaryFragment)
-Secondary (adds the SecondaryFragment)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:orientation="vertical"
tools:context="com.yuv.mycollege.MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/button_primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Primary"/>
<Button
android:id="#+id/button_secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Secondary"/>
</LinearLayout>
<!-- Main content area for fragments-->
<FrameLayout
android:background="#color/colorPrimary"
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="4dp"/>
</LinearLayout>
Both the fragments has content and footer area, which are themselves are fragments (PrimaryContentFragment, PrimaryFooterFragment, SecondaryContentFragment, SecondaryFooterFragment)
I am adding the fragments from the activity using:
public void onClick(View view) {
Button button = (Button)view;
Toast.makeText(this, "Going to Add Children", Toast.LENGTH_SHORT).show();
switch(view.getId()) {
case R.id.button_primary:
getSupportFragmentManager().beginTransaction()
.replace(R.id.main_container, new PrimaryFragment())
.addToBackStack("primary")
.commit();
break;
case R.id.button_secondary:
getSupportFragmentManager().beginTransaction()
.replace(R.id.main_container, new SecondaryFragment())
.addToBackStack("secondary")
.commit();
break;
}
}
And, finally adding the each children fragments using:
The layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/content_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#color/colorAccent"
android:layout_weight="8"
></FrameLayout>
<FrameLayout
android:id="#+id/footer_container"
android:background="#color/colorPrimaryDark"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
></FrameLayout>
</LinearLayout>
The children fragments adding:
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.primary_fragment, container, false);
getChildFragmentManager()
.beginTransaction()
.add(R.id.content_container, new PrimaryContentFragment())
.add(R.id.footer_container, new PrimaryFooterFragment())
.addToBackStack("primarychildren")
.commit();
return view;
}
I am adding the similar logics for the another fragment also and so on for the rest which is working.
THE PROBLEM:
The solution as stated is working but seems as very raw naive approach. Could anybody suggest the better architecture I could follow such as:
all the fragments (Primary/Secondary/...) uses the same designs so
can I create some base class to inherit common features
all the footer are similar for all of fragments but with simple text change
(might be like breadcrumb) So, Can I use same footer for all
fragments with some settext method ...
how can I effectively communicate between activity and fragments
BEING A NEW ANDROID DEV, MY ONLY CONCERN IS AM I DOING THE RIGHT WAY !!!
Try this using bundle :-
ContentFragment content=new ContentFragment();
content.setArguments( ( new Bundle()).putString("value","primary"));
getChildFragmentManager()
.beginTransaction()
.add(R.id.content_container, content)
.add(R.id.footer_container, new PrimaryFooterFragment())
.addToBackStack("primarychildren")
.commit();
Similarly For secondary use :-
ContentFragment content=new ContentFragment();
content.setArguments( ( new Bundle()).putString("value","secondary"));
Use same content and footer fragments just set the texts by using bundle arguments
All the fragments (Primary/Secondary/...) uses the same designs so can
I create some base class to inherit common features
If they are using the same design and with slight changes in their content, then there's no need of create different Fragment classes. You can just pass necessary values from your calling Activity or Fragment to populate the contents in each of your child fragments.
All the footer are similar for all of fragments but with simple text
change (might be like breadcrumb) So, Can I use same footer for all
fragments with some settext method ...
If they are just simple text changes, then please use the setArguments and getArguments methods to pass values between Fragments rather creating different Fragment classes.
Here's how you can pass values between fragments. And here's how you can pass data from your Activity to Fragment.
How can I effectively communicate between activity and fragments
Please follow the two links above to communicate between Activity and Fragment.
Update
Following up the comment, as you have said that the PrimaryFragment and SecondaryFragment are mostly likely, I would suggest you to have one single Fragment having all these. Instead of having PrimaryFragment, SecondaryFragment and a CommonFragment, you might consider a single Fragment having the footer Fragment as well. When you are about to launch an instance of that Fragment, just pass necessary values to populate data as the contents of those Fragment.
Please let me know if I have not clarified enough.

Activity to fragment 1, fragment 1 to fragment 2 fragment 2 to Activity

I am beginner in Android development. I am creating a small application in which i call two fragment from single activity.
Activity -> fragment 1->fragment 2.
Activity to fragment 1, fragment 1 to fragment 2.
I want to know how i directly call fragment 2 to Activity directly.
I give button in Fragment 2, on click of that button I want go in Activity.
The activity already exists. Your activity is the one hosting the fragments i.e assuming all are full screen fragments, when you call fragment1, your activity removes the present fragment (if there is any) and replaces it with fragment1, when you call fragment2, fragment1 is replaced with fragment2 and so on.
If you want to see only the layout of the activity (which in most cases would be just a white screen), you have to remove all fragments, to do that, add this to your button's onClick:
getActivity().getFragmentManager().popBackStack(1, FragmentManager.POP_BACK_STACK_INCLUSIVE);
By your question I notice that you still need to read about fragments.
you can't go to an activity from a fragment because the fragments
are a section of an activity, which has its own lifecycle, receives its own input events, you can add or remove them while the activity is running (sort of like a "sub activity" that you can reuse in different activities).
Although you can replace a fragment and use a different one on the same activity.
you can do so like this:
First in main xml use a layout that your going to inflate:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/frgContainer"
android:layout_margin="20dp"
android:background="#00e6ff">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btn"
android:text="btn"
/>
</LinearLayout>
Create 2 new activities which will be our fragments with an xml files you can add anything you wish to it:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
tools:context="com.example.hackeru.mydynamicfragment.Login">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="User Name"
android:id="#+id/txtLoginUser"
android:layout_marginLeft="20sp"
android:layout_marginRight="20sp"
android:layout_marginTop="80dp"
/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Password"
android:id="#+id/txtLoginPass"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btnLogin"
android:text="Login"
/>
</LinearLayout>
Override onCreate method on the fragment
public class Login extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_login,container,false);
}
4.use fragmentTransaction in the onClick method in main to replace or add current layout with the fragment you created:
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager =getFragmentManager();
// we must handle the callback fragment process
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
Login loginFragment = new Login();
fragmentTransaction.add(R.id.frgContainer,loginFragment);
// fragmentTransaction.replace if there is another fragment you
// wish to replace
fragmentTransaction.commit();
}
read this:
https://developer.android.com/guide/components/fragments.html

Implementing Fragments Androids

I am implementing fragments for the first time so please help me.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="#+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="#+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
I want that fragment having the id as 'list' should remain constant but the the fragment having id 'viewer' should be able to call different classes.
(Note that the classes extend Activity.)
My question is simple: I have four classes(Extending ACTIVITY). I want to divide the screen into two parts. The left Side remains constant which contains the listview. On list view's click I want to open my Class(Extending ACTIVITY), but only in the right portion(remaining screen).
It is a basic question. You should start from here. And this topic can help you also.
Fragments are like seperate acticities, so unless u make the changes the action on one fragment will not affect the other fragments.
Assuming u have a listview on the left fragment, in its activity place a onItemClickListener.
For each itemclick switch the activity on the right fragment.
Sample Code for the OnItemClick Event
Fragment fragment=new activity1();
fragmentManager fm=getFragmentManager();
FragmentTransaction ft=fm.beginTransaction();
ft.replace(R.id.frame2,fragment);
ft.commit();
In the above code segment activity1 is the new class want to attach to the right fragment. R.id.frame2 is the id of the framelayout that is used with the right fragment.
According to the android documentation of fragments:
A Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a "sub activity" that you can reuse in different activities).
http://developer.android.com/guide/components/fragments.html
what i understood from your question is that you want to the content of your fragement viewer at run-time. a possible solution which i can suggest for this is:
Instead of your four classes extending Activity, extend Fragment, each having its own layout. Modify the main layout file to look something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="#+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" >
</FrameLayout>
</LinearLayout>
the FrameLayout will basically act as a container for your fragments, which you can dynamically load at run-time(by clicking the ListView). This tutorial will help you out with it:
http://developer.android.com/training/basics/fragments/fragment-ui.html
Hope my answer helps you in some way.
The Fragment class can be used many ways to achieve a wide variety of results. In its core, it represents a particular operation or interface that is running within a larger Activity. A Fragment is closely tied to the Activity it is in, and can not be used apart from one. Though Fragment defines its own lifecycle, that lifecycle is dependent on its activity: if the activity is stopped, no fragments inside of it can be started; when the activity is destroyed, all fragments will be destroyed.
MyFragment newFragment = new MyFragment();// MyFragment is a Fragment class
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.fra,newFragment, tag);
transaction.addToBackStack(null);
transaction.commit();
sample code
in sample code change
ft.add(android.R.id.content,fragTwo, "tag");
to
ft.add(R.id.fra,fragTwo, "tag");
and add some code in detail.java
public void onStart() {
// TODO Auto-generated method stub
tv.setText(data);
b.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragTwo = new MyFragment();
//String tag = getActivity().GetFragmentID();
Fragment f= fm.findFragmentById(getId());
ft.replace(R.id.fra,fragTwo, "tag");
ft.hide(f);
ft.commit();
}
});
super.onStart();
}

how to get a fragment added in an XML layout

I have a layout which includes a fragment as follows:
<fragment
android:id="#+id/mainImagesList"
android:name="com.guc.project.ImagesList"
android:layout_width="match_parent"
android:layout_height="62dp"
android:layout_below="#+id/addimagebutton"
android:layout_weight="1"
android:paddingTop="55dp" />
now, I need to get this fragment and cast it so I can manipulate it and the updates appear. How can i do so ?!
EDIT: I think I've managed to get the fragment, but when I change some variables, the changes don't appear !
You can get the fragment instance as follows:
getSupportFragmentManager().findFragmentById(R.id.yourFragmentId)
If the fragment is embedded in another fragment, you need getChildFragmentManager() but not getFragmentManager().
For example, in layout xml define the fragment like this:
<fragment
android:name="com.aventlabs.ChatFragment"
android:id="#+id/chatfragment"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginTop="50dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" />
in Code, you can get the fragment instance like this:
FragmentManager f = getChildFragmentManager();
FragmentTransaction transaction = f.beginTransaction();
chatFragment = f.findFragmentById(R.id.chatfragment);
if (chatFragment != null) {
transaction.hide(chatFragment);
}
transaction.commit();
I did exactly the same in android and the simplest way to do this in using interfaces. I had an activity with 6 fragments and i needed to update only 3 of them.
I use this
final Integer numeroFragments = ((PagerAdapterOfe) mViewPager.getAdapter()).getCount();
for (int i=0; i<numeroFragments; i++) {
Object fragment = ((PagerAdapterOfe) mViewPager.getAdapter()).getItem(i);
// If the fragment implement my interface, update the list
if (fragment instanceof IOfertaFragment){
((IOfertaFragment) fragment).actualizaListaOfertas();
}
}
Where, PageAdapterOfe is my activity fragments adapter. I loop all of my fragments and search for those that implement my interface, when i found one, I execute the method defined by my interface and that is!
I use this code inside the activity that holds all the fragments, in response a broadcast signal, you can put it where you need.
The interface:
public interface IOfertaFragment {
public void actualizaListaOfertas();
}
You can find the fragment using findFragmentById (if you know the component it is included in) or by findFragmentByTag (if you know its tag)
I don't know which variables you want to update, but you can replace the fragment with another fragment using the FragmentTransaction API.
See http://developer.android.com/guide/components/fragments.html for examples.
If Fragment is included inside the layout file of Activity then it can be referenced by SupportFragmentManager like...
MyFragment myFragment= (MyFragment)getSupportFragmentManager().findFragmentById(R.id.FRAGMENTID)
If Fragment is included inside the layout file of another Fragment then it can be referenced by ChildFragmentManager like...
MyFragment myFragment= (MyFragment)getChildFragmentManager().findFragmentById(R.id.FRAGMENTID)

findFragmentById always returns null

I'm defining an ID for my fragment in the xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test_fragment"
...
Then I add this fragment in the activity's onCreate method:
MyFragment myFragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_container, myFragment);
fragmentTransaction.commit();
This is all working fine. Replacing fragments and is also working.
Later I'm trying to retrieve this fragment by its ID in one of the activity's methods:
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.test_fragment);
Doing so leads to myFragment being null. Always.
When I try to do the same with tags instead of IDs I can retrieve the fragment by its tag without any problems:
MyFragment myFragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_container, myFragment, "testfragment");
fragmentTransaction.commit();
...
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentByTag("testfragment");
Why can't findFragmentById find the fragment, but findFragmentByTag does so? Am I missing something?
R.id.test_fragment is not the ID of your fragment but the id of your LinearLayout
Calling add(int containerViewId, Fragment fragment) will add a fragment without a tag.
So or you use add(int containerViewId, Fragment fragment, String tag) and you get back your fragment using your tag (as an ID)
Use the <FrameLayout> tag as a container in your layout file. Later to replace the fragments from your activity dynamically, you can use the ID of the <FrameLayout> container to replace the fragments in your activity.
<FrameLayout
android:id="#+id/test_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test_fragment"
it should be a fragment not a LinearLayout
<fragment android:name="com.example.yourfragment"
android:id="#+id/test_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
I was using android.support.v4.app.Fragment in my layout while calling getFragmentManager() which actually searched for android.app.Fragment subclasses and I got null.
So the fix was to call getSupportFragmentManager() instead.
In general make sure the package of a fragment you are subclassing and using in your layout is the same returned by the corresponding FragmentManager which performs search.
Or, you should have instead used :
(MyFragment) getFragmentManager().findFragmentById(R.id.fragment_container);
R.id.test_fragment is your LinearLayout ID not your Fragment.
You can define and id on a fragment when it is inflated from an xml like in this sample http://developer.android.com/guide/topics/fundamentals/fragments.html#Adding
The reasons mentioned above are valid but another possible reason is that you are trying to search for the fragment while being in a fragment this also results in fragmentManager.findFragmentById to return null. We should use childFragmentManager.findFragmentById to find the fragment inside a fragment.
According to the official documentation.
public final androidx.fragment.app.FragmentManager getChildFragmentManager()
Return a private FragmentManager for placing and managing Fragments
inside of this Fragment.
FragmentB fragmentB =
(FragmentB) getSupportFragmentManager().findFragmentById(R.id.containerb);
if(fragmentB != null)
{
fragmentB.showuserResponse(msg);
}
Use container id as fragment id. And then check for null reference.
fragmentTransaction.add(R.id.fragment_container, myFragment);
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.test_fragment);
Please notice the difference.
You should pass R.id.fragment_container as the argument to findFragmentById, as you pass it to the add function, instead of R.id.test_fragment
By the way , according to the inner implementation of the two functions, it should be right that the id can be
that of its container view.

Categories

Resources