You will understand my problem if you do it step by step as mentioned below (sorry, But I can't make you understand in other way). This might be confusing. But, I am sure if you read it once, you will understand.
Create a new android project, then create two Fragments. You will now
have
a. MainActivity.java.
b. FirstFragment(FirstFragment.java) with it's xml
file(first_fragment.xml).
c. SecondFragment(SecondFragment.java) with it's xml
file(second_fragment.xml).
Now create a custom linearLayout class (FormRow.java) as below:
public class FormRowNew extends LinearLayout {
public FormRowNew(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
View.inflate(getContext(), R.layout.form_row, this);
}
}
xml file (form_row) in this is like:
<?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="wrap_content"
android:orientation="vertical">
<EditText
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="eeeee"/>
</LinearLayout>
Use this Custom linear class TWICE inside FirstFragment like below:
<gallery.com.yyyyyyyyy.FormRow
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/txvFirst"
>
</gallery.com.yyyyyyyyy.FormRow>
<gallery.com.yyyyyyyyy.FormRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/first"
>
</gallery.com.yyyyyyyyy.FormRow>
REMEMBER: I have used it twice. You also use it AT LEAST TWICE.
Now, load FirstFragment in MainActivity.java at some id (rlRootLayout) like below.
FirstFragment firstFragment = new FirstFragment();
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.replace(R.id.rlRootLayout, firstFragment).commit();
Similarly, load Second Fragment at same ID (rlRootLayout) from FirstFragment like below.
secondFragment blankFragment = new secondFragment();
getActivity().getSupportFragmentManager().beginTransaction()
.addToBackS tack(null).replace(R.id.rlRootLayout, blankFragment)
.commit();
Here i am adding SecondFragment to MainActivity from FirstFragment
at ID(rlRootLayout).
Problem :- Run the app and go to page as mentioned :
MainActivity ->
FirstFragment ->
Change something in BOTTOM FormRow(like add some text in EditText) ->
SecondFragment ->
FirstFragment.
Now, See the custom classes (FormRow) inside FirstFragment.
Whatever We had added in bottom FormRow class, automatically added in Top FormRow. I couldn't find the reason why is this happening. Even if I am doing nothing with top FormRow, it changes according to bottom when I come back from SecondFragment.
Please help.
That behavior is because of the id of the EditText. When the first fragment is inflating the layout while going back from the second fragment, the it assigns the values to edit text by using it id. So in this case both EditText's has the same id so it assigns the same value for the both Edittexts's
Save the text in editText while adding second fragment. Then set those saved text while going back to first from second this
#Override
public void onViewStateRestored(#Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
//set edit text
}
is called.
Related
I'm adding fragments to my activity in way that I first hide current fragment and then add new one. My problem is that when I show my new fragment and start interacting with him, it also interacts with previous one.
The code which I use to add new and hide current fragment is:
public void add(int containerViewId, Fragment fragment, boolean addToBackStack){
FragmentTransaction ft = fragmentManager.beginTransaction().hide(currentFragment).add(containerViewId, fragment);
if (addToBackStack){
ft.addToBackStack(null);
}
ft.commit();
currentFragment = fragment;
backStackCount++;
}
What is going on, and how to hide fragment so I can interact only with the last one added? replace is not an option because I don't want to remove current fragment.
I also had similar problem. I don't know what possibly is creating this issue but what I did to resolve it is that I set an onclick listener to the outermost layout of my fragment.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/top_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:clickable="false"
android:orientation="vertical"
tools:context=".Fragments.TopicsFragment">
...other components
</LinearLayout>
In fragment:
LinearLayout topLayout = (LinearLayout) fragmentView.findViewById(R.id.top_layout);
topLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//do nothing
}
});
Also you might see I have added a background #FFFFFF to this outermost layout, because in mycase the content of previous fragment was also visible behind the new one. So this solved that problem too.
Good morning. I'm developing an app in which I have a main layout that extends from activity and inside this one I have one fragment of one data type, in my case FragmentCover (it's a class).
During my app, I push a button and I want to change this fragment layout for another layout that extends from fragment but of different type, called SongList.
My problem is that I have defined this fragment for the class of Cover and when I change I don't have any problem, but when I want to get the views and set to one variable of my class, the funciont songList = (ListView) getView().findViewById(R.id.songList); it's null and it gives me error.
I put it here what I do.
layout
<fragment android:name="es.xxx.ui.FragmentCover"
android:id="#+id/pruebaa"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#id/songBar"
android:layout_below="#id/header"/>
mainclass change
public void onClick(View v) {
if(isCoverFragment){
FragmentSongList fragmentSongList = new FragmentSongList();
transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.pruebaa, fragmentSongList);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.addToBackStack("LIST");
transaction.commit();
isCoverFragment=false;
}
else{
transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.pruebaa, fragmentCover);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.addToBackStack("COVER");
transaction.commit();
getSongCover();
isCoverFragment=true;
}
The problem is not the change, is when I try to make the findViewById, it's probabbly because it doesn't load the view associated with FragmentSongList.
You need to use a FrameLayout inside your layout file, instead of defining the Fragment in .xml
Into that FrameLayout, you can inflate any Fragment you want.
Just inflate the First Fragment you want to be displayed directly in your onCreate(...) method.
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
This is how to inflate the Fragments programatically into the FrameLayout.
FragmentSongList fragmentSongList = new FragmentSongList();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.content_frame, fragmentSongList);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.addToBackStack("LIST");
transaction.commit();
You can leave the code inside your onClick() method just the way it is, just change the id to "content_frame". Furthermore, as mentioned above you will have to inflate the first Fragment that should be displayed inside your onCreate(...) method.
I have an activity that has a ViewPager in the layout.
I have two fragments which display, one for each tab.
One of the fragments is designed to host other fragments - this is the CustomerMainFragment which inflates fragment_customer_main:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lyt_customer_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/fragment_customer_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
This then adds CustomerSearchFragment to the FrameLayout which inflates fragment_customer_search.
CustomerSearchFragment also has the following override to switch out the search fragment for a detail fragment on a button press:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button btnSearch1 = (Button) view.findViewById(R.id.button1);
if (btnSearch1 != null) {
btnSearch1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// This is important bit
Fragment customerDetailFragment = new CustomerDetailFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.addToBackStack(null);
transaction.replace(R.id.fragment_customer_content, customerDetailFragment).commit();
}
});
}
}
After clicking the button I get the following error:
java.lang.IllegalArgumentException: No view found for id 0x7f080006
(com.chrisbeckyapps.sample:id/fragment_customer_content) for fragment
CustomerDetailFragment{4280b0b8 #0 id=0x7f080006}
I'm new to fragments and understand the concepts, but I'm stumped by this. I originally had the search fragment going straight into the pager, but then replacing it with the detail fragment mean it just showed over the top, and my research led to this being a better solution.
I have wondered about trying to move the search logic to the CustomerMainFragment but this means hooking up a lot of logic and I thought you could embed logic within fragments.
Suggestions?
Sorry, just found such a simple fix.
In my onclick handler, I just had to change from getChildFragmentManager to getFragmentManager
I have an activity with several tabs (using the 'fixed tabs + swipe' style). Each tab layout is defined as a fragment xml file.
Eg, my activity is called ModifyCustActivity. This uses an almost-empty xml file called activity_modify_cust.xml. Each tab on this page is represented by various xml files such as fragment_modify_cust_basic and fragment_modify_cust_address etc etc. Each of these fragment xml files contains EditTexts, Spinners and more.
When the activity starts, I need to be able to access these views from the activity code, as I need to pre-populate them, and get their results once they are edited. However, because these views exist in a fragment xml file, I don't seem to be able to reach them in code. Is there a way to access a view contained in a fragment xml file?
Is there a way to access a view contained in a fragment xml file?
Yes it is, but your fragment should be declared in the XML layout file, which seems to be your case.
For example:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...">
<fragment
android:name="com.example.MyFragment"
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
And you would access the fragment like this:
FragmentManager manager = getSupportFragmentManager();
MyFragment fragment = (MyFragment)manager.findFragmentById(R.id.my_fragment);
Then using the fragment instance you could further access your views, for example by calling a public method from the fragment which updates some particular view.
UPDATE:
Suppose you have a TextView that appears in layout of the fragment, and need to update from the activity.
Let this be the fragment class:
public class MyFragment extends Fragment{
private TextView textView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, null, false);
textView = (TextView)view.findViewById(R.id.textView);
return view;
}
public void updateTextView(String text){
textView.setText(text);
}
}
Then you would update the TextView by calling in your activity the updateTextView() method:
fragment.updateTextView("text");
You can reach fragments views from activity. If you want to send a data from fragment to another fragment. Your sender fragment must communicate with activity and your activity can manipulate the view in other fragment
http://developer.android.com/training/basics/fragments/communicating.html
I have created an xml file called editor.xml which contains a FrameLayout. In my main activity I am trying to add my custom fragment to my FrameLayout.
The error I receive when trying to add my fragment is:
The method add(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, editorFrag)
However my editorFrag extends Fragment so I am confused on why this is happening. Below is my code for the files I have mentioned. Any help is appreciated.
Editor.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
editorFrag.java
public class editorFrag extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// Inflate the layout for this fragment
return inflater.inflate(R.layout.newlevel, container, false);
}
}
MainActivity.java
public class editorActivity extends FragmentActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.editor);
// Check that the activity is using the layout version with the fragment_container FrameLayout
if(findViewById(R.id.fragment_container) != null)
{
// if we are being restored from a previous state, then we dont need to do anything and should
// return or else we could end up with overlapping fragments.
if(savedInstanceState != null)
return;
// Create an instance of editorFrag
editorFrag firstFrag = new editorFrag();
// add fragment to the fragment container layout
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, firstFrag);
}
}
}
Answered:
Luksprog answered this problem for me below by telling me to check my imports. Eclipse chose to import the SDK version of Fragment instead of the support version that I needed. Thank you for the help.
You forgot to commit() your transaction.
You also forgot to call the addtoBackStack() method, otherwise your app closes when you hit the back button.
add commit() like this
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, firstFrag).commit();
1- //Add fragment container in xml file
<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>
2- //Implementation of BackStack
fragmentTransaction.setReorderingAllowed(true);
fragmentTransaction.addToBackStack("name");