Android relationships between fragments - android

I'm using some fragments programmatically in activity. There is one button in my first fragment and when i click to this button, it replaces to second fragment.My second fragment's background is 90% transparent, and when it starts, i can see button which is situated in first fragment, and it also works. I want to stop or do something, because i dont want to see first fragment features and use it.
First Fragment
public class RegistrationFirstFragment extends Fragment {
RegistrationSecondFragment rf;
ImageButton btnNewUser,btnNewAgent;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//return super.onCreateView(inflater, container, savedInstanceState);
View v =inflater.inflate(R.layout.fragment_registration_first,container,false);
rf = new RegistrationSecondFragment();
btnNewUser = (ImageButton)v.findViewById(R.id.btnNewUserRegistrationFirstFragment);
btnNewAgent = (ImageButton)v.findViewById(R.id.btnNewAgentRegistrationFirstFragment);
btnNewUser.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(), "Transaction completed succesfully", Toast.LENGTH_LONG).show();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.flRegistrationFirst, rf);
ft.commit();
}
});
return v;
}
}
Second Fragment
public class RegistrationSecondFragment extends Fragment {
RegistrationFirstFragment rtl;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rtl = new RegistrationFirstFragment();
//return super.onCreateView(inflater, container, savedInstanceState);
View v =inflater.inflate(R.layout.fragment_registration_second,container,false);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
// ft.replace(R.id.flRegistrationFirst, rf);
ft.remove(rtl);
ft.commit();
return v;
}
}
Main Activity
public class RegistrationActivity extends AppCompatActivity{
RegistrationFirstFragment fr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registration);
fr = new RegistrationFirstFragment();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.flRegistrationFragment,fr);
ft.commit();
}
}

You can put
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
(the parameter fragment would be an instance of your second fragment)
into your onClick(View view){...} method to change the fragment instead of adding it.
Next time code for understanding your problem btw ;)

Add to fragment layout android:clickable="true". Int his way fragment will catch event so the click will not be caught by "main fragment".
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />

Give android:clickable="true" for Second Fragment root layout parent, when ever fragment opens It catches the click event of root and ignored previous click events.
Second One: If u use replace Fragment it's better than add fragment.
getActivity().getSupportFragmentManager().beginTransaction().replace
(R.id.YOUR_CONTAINER, 'FragmentObject').addToBackStack("TAG").commitAllowingStateLoss();

Related

replace fragment with another fragment along with remove view

I have one activity and two Fragments. FragmentA and FragmentB.
I need to implement like, Initially FragmentA should be there.
and After Button click FragmentB should be there.
in my condition when activity is being displayed,fragmentA is showing and when click to button,fragmentB placed at the bottom of fragmentA and do not replace FragmentA
My activity Code is:
public class FragmentActivity extends AppCompatActivity {
FrameLayout activityFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
activityFragment = (FrameLayout) findViewById(R.id.activityFragment);
Fragment fragment = new FragmentA();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.activityFragment, fragment);
transaction.commit();
}
public void goToFrag(View view) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment fragment = new FragmentB();
transaction.add(R.id.fragmentRoot, fragment);
transaction.commit();
}
}
my first fragment code:
public class FragmentA extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view=inflater.inflate(R.layout.fragment_a,container,false);
return view;
}
}
my second fragment code:
public class FragmentB extends Fragment {
public FragmentB() {
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view=inflater.inflate(R.layout.fragment_b,container,false);
return view;
}
}
First of all, you should always have a FrameLayout in xml to replace your fragments there, then you use different containers to add fragments activityFragment and fragmentRoot .You should replace fragments in one container. You can use either add or replace for FragmentManager , so it activityFragment is your container (which should be a framelayout as a wrapper as the docs suggest) you use
public void goToFrag(View view) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment fragment = new FragmentB();
transaction.replace(R.id.activityFragment, fragment); // use the same container where you switch A and B
transaction.commit();
}

nullpointer running method of fragment from activity when using views

My Fragment
public class CustomFrag extends Fragment {
private Button btn;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.button_fragment, container, false);
btn = (Button)view.findViewById(R.id.button1);
return view;
}
public void sendItem(String item) {
btn.setText(item);
}
}
And in my activity
public void loadFragment(String data) {
// Load up new fragment
Fragment fragment = new CustomFrag();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.contentFragment, fragment, "custFrag");
transaction.addToBackStack("custFrag");
transaction.commit();
// Required before calling fragment methods
getSupportFragmentManager().executePendingTransactions();
// Load fragment with data
CustomFrag frag = (CustomFrag) getSupportFragmentManager().findFragmentByTag("custFrag");
frag.sendItem(data);
}
I'm getting a nullpointer exception any time I attempt to use the views of my fragment. If I try to load the view inside the method as well, it will not work
i.e. inside sendItem()
btn = (Button)getView().findViewById(R.id.button1);
My layout (button_fragment) contains the button:
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Because you have executed the transaction does not mean that the fragment has actually created its view. Which is why btn is still null.
To pass data from the activity to the fragment, use the argument bundle:
Fragment fragment = new CustomFrag();
Bundle args = new Bundle();
args.putString("item", data);
fragment.setArguments(args);
Then, in onCreateView:
btn = (Button)view.findViewById(R.id.button1);
btn.setText(getArguments().getString("item"));
See this Best practice for instantiating a new Android Fragment question and the first answer.
The problem here is that the fragment's layout is not drawn yet when sendItem(...) is called. Which means btn is null at that point. Instead, this is how you're supposed to do it (see http://developer.android.com/guide/components/fragments.html):
public class CustomFrag extends Fragment {
private Button btn;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.button_fragment, container, false);
btn = (Button)view.findViewById(R.id.button1);
btn.setText(getArguments.getString("item"));
return view;
}
}
And
public void loadFragment(String data) {
// Load up new fragment
Fragment fragment = new CustomFrag();
Bundle args = new Bundle();
args.putString("item", data);
fragment.setArguments(args);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.contentFragment, fragment, "custFrag");
transaction.addToBackStack("custFrag");
transaction.commit();
// Required before calling fragment methods
getSupportFragmentManager().executePendingTransactions();
}
Edit:
njzk2 was faster, but I hope the details I gave will help you further. In any case, the link he gave explains nicely why you should do it like that.

How to move from one fragment to another fragment on click of an ImageView in Android?

I have an ImageView. I want to move from one fragment to another fragment on a click of an Imageview, the same way like we can move from one activity to another using
Intent i=new Intent(MainActivity.this,SecondActivity.class);
startActivity(i);
How can I do this? Can anyone explain to me step by step?
My codes are as follows:
mycontacts.class
public class mycontacts extends Fragment {
public mycontacts() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View v = super.getView(position, convertView, parent);
ImageView purple=(ImageView)v.findViewById(R.id.imageView1);
purple.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//how to go to tasks fragment from here???
}
});
return view;
}
}
tasks.class
public class tasks extends Fragment {
public tasks() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout_one, container,
false);
return view;
}
}
purple.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = new tasks();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_frame, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
You write the above code...there we are replacing R.id.content_frame with our fragment.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_profile, container, false);
notification = (ImageView)v.findViewById(R.id.notification);
notification.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentTransaction fr = getFragmentManager().beginTransaction();
fr.replace(R.id.container,new NotificationFragment());
fr.commit();
}
});
return v;
}
Add this code where you want to click and load Fragment.
Fragment fragment = new yourfragment();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
When you are inside an activity and need to go to a fragment use below
getFragmentManager().beginTransaction().replace(R.id.*TO_BE_REPLACED_LAYOUT_ID*, new tasks()).commit();
But when you are inside a fragment and need to go to a fragment then just add a getActivity(). before, so it would become
getActivity().getFragmentManager().beginTransaction().replace(R.id.*TO_BE_REPLACED_LAYOUT_ID*, new tasks()).commit();
as simple as that.
The *TO_BE_REPLACED_LAYOUT_ID* can be the entire page of activity or a part of it, just make sure to put an id to the layout to be replaced. It is general practice to put the replaceable layout in a FrameLayout .
inside your onClickListener.onClick, put
getFragmentManager().beginTransaction().replace(R.id.container, new tasks()).commit();
In another word, in your mycontacts.class
public class mycontacts extends Fragment {
public mycontacts() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View v = super.getView(position, convertView, parent);
ImageView purple = (ImageView) v.findViewById(R.id.imageView1);
purple.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
getFragmentManager()
.beginTransaction()
.replace(R.id.container, new tasks())
.commit();
}
});
return view;
}
}
now, remember R.id.container is the container (FrameLayout or other layouts) for the activity that calls the fragment
You can move to another fragment by using the FragmentManager transactions. Fragment can not be called like activities,. Fragments exists on the existence of activities.
You can call another fragment by writing the code below:
FragmentTransaction t = this.getFragmentManager().beginTransaction();
Fragment mFrag = new MyFragment();
t.replace(R.id.content_frame, mFrag);
t.commit();
here "R.id.content_frame" is the id of the layout on which you want to replace the fragment.
You can also add the other fragment incase of replace.
If you're looking for the Kotlin version of the above code, you can do it in this way, and you call replaceFragment(RequiredFragment()) at onClickListener or wherever you want.
private fun replaceFragment(fragment: Fragment) {
val transaction = activity!!.supportFragmentManager.beginTransaction()
transaction.replace(R.id.frame, fragment)
transaction.commit()
}
private boolean loadFragment(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fl_fragment_container, fragment)
.commit();
return true;
}
return false;
}
in kotlin, put inside of your current running fragment button.setOnClickListener
val bpfragment = TwoFragment()
activity?.supportFragmentManager?.beginTransaction()?.replace(R.id.fragment_container, bpfragment)?.commit()
val fragment = YourFragment3()
val fm : FragmentManager= requireActivity().supportFragmentManager
val ft: FragmentTransaction = fm.beginTransaction()
ft.replace(R.id.container, fragment)
ft.commit()
(activity as MainActivity).binding.viewPager.setCurrentItem(2)
We can use this one-
purple.setOnClickListener(view1 -> {
Fragment fragment = new task();
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
});

Fragments the right way

I'm trying out some fragments right now. I've got a fragment with a button and when I click that button I switch to another fragment. Now when I push on the back button I return to the first fragment that's good. Now when I click again on that button a new fragment is started. So I always start a new fragment. I think thats not the way it needs to be done. Is there a better way to for example resume the already created fragment?
My code:
public static class PlaceholderFragment extends Fragment{
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
Button test = (Button)rootView.findViewById(R.id.button);
test.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View view)
{
Log.d("Test", "Button clicked.");
TestFrag newFragment = new TestFrag();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
return rootView;
}
}
public static class TestFrag extends Fragment {
public TestFrag() {
Log.d("Test","New fragment");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main2, container, false);
return rootView;
}
}
When you use the fragment transaction you can specify a tag for the fragment
fragmentTransaction.add(R.id.main_fragment, newFragment, fragTag);
fragmentTransaction.commit();
Then later you can find a fragment by tag from the fragmentManager
newFragment = fragMan.findFragmentByTag(fragTag);
if newFragment then is null you should create the Fragment since it wasnt found by the tag
Thanks to Joakim:
fragmentTransaction.add(R.id.main_fragment, newFragment, fragTag); fragmentTransaction.commit();
Then later you can find a fragment by tag from the fragmentManager
newFragment = fragMan.findFragmentByTag(fragTag); if newFragment then is null you should create the Fragment since it wasnt found by the tag. If the tag isn't null you can just add and commit the new one.

Replacing a fragment with another fragment of the same class

I have a fragment (let's call it MyFragment) that inflates different layouts according to a parameter passed in the arguments.
All works well if MyFragment is started from a different fragment. But if MyFragment is active and I want to launch a new MyFragment with a different layout parameter, the fragmentManager does not create a new fragment at all.
data.setInt("Layout index",i);
fragmentTab0 = (Fragment) new MyFragment();
fragmentTab0.setArguments(data);
fragmentTransaction.replace(R.id.fragmentContent, fragmentTab0, "MY");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
How can I force convince the fragmentTransaction to launch the fragment again?
NOTE: The important point here is I need to inflate again a layout, which is different from the layout inflated before. The code looks like:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
switch( getArguments().getInt("Layout index") ) {
case 1:
rootView = inflater.inflate(R.layout.firstlayout, container, false);
break;
case 2:
rootView = inflater.inflate(R.layout.secondlayout, container, false);
break;
case 3:
rootView = inflater.inflate(R.layout.thirdlayout, container, false);
break;
default: break;
}
Bypass Solution
Explanation (hoover to see it)
Since the source code for fragmentTransaction.replace/add/remove is
not available I could not find what really happens. But it is
reasonable to think that at some point it compares the current class
name with the replacement class name and it exits if they are the
same.. Thanks to #devconsole for pointing out the source
code. I know now why this happens. The FragmentManager.removeFragment()
method does not reset the fragment state, it remains RESUMED, then the
method moveToState(CREATED) only initilizes a fragment if (f.mState <
newState) = if (RESUMED < CREATED) = false. Else, ergo, it just resumes the fragment.
So to solve this problem I created an almost empty fragment which only purpose is to replace itself with the target fragment.
public class JumpFragment {
public JumpFragment() {
}
#Override
public void onStart() {
Bundle data = getArguments();
int containerId = data.getString("containerID");
String tag = data.getString("tag");
//Class<?> c = data.get???("class");
//Fragment f = (Fragment) c.newInstance();
Fragment f = (Fragment) new MyFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
f.setArguments(data);
fragmentTransaction.replace(containerId, f, tag);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
And I use it:
data.setInt("Layout index",i);
data.setInt("containerID",R.id.fragmentContent);
data.setString("tag","MY");
fragmentTab0 = (Fragment) new JumpFragment();
fragmentTab0.setArguments(data);
fragmentTransaction.replace(R.id.fragmentContent, fragmentTab0);
fragmentTransaction.commit();
Now no fragment is replaced by a same class fragment:
MyFragment -> JumpFragment -> MyFragment
I haven't figured out how to pass the class through the arguments bundle, to make it totally generic.
The following worked without problems for me. Notice that I used the Android Support Library.
activity_main.xml:
<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"
tools:context=".MainActivity" >
<Button
android:id="#+id/button_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ONE" />
<Button
android:id="#+id/button_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/button_one"
android:text="TWO" />
<FrameLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/button_one" >
</FrameLayout>
</RelativeLayout>
MainActivity.java:
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment fragment = DetailsFragment.newInstance("INITIAL");
transaction.add(R.id.main_container, fragment);
transaction.commit();
}
findViewById(R.id.button_one).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
update("Button 1 clicked");
}
});
findViewById(R.id.button_two).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
update("Button 2 clicked");
}
});
}
protected void update(String value) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment fragment = DetailsFragment.newInstance(value);
transaction.replace(R.id.main_container, fragment);
transaction.commit();
}
public static final class DetailsFragment extends Fragment {
public static DetailsFragment newInstance(String param) {
DetailsFragment fragment = new DetailsFragment();
Bundle args = new Bundle();
args.putString("param", param);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView textView = new TextView(container.getContext());
textView.setText(getArguments().getString("param"));
return textView;
}
}
}
Did you try to first remove your fragment with remove(fragMgr.findFragmentByTag("MY"))and then add the new one ?
PS : I assume you don't keep any reference to this fragment.
If I understand you correctly: the fragment you want to replace what is currently being displayed and the user does something to cause it to re-display itself?
If this is correct then have done something similar this way:
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View V = inflater.inflate(R.layout.myLayout, container, false);
// Call method that fills the layout with data
displayData(V);
// Put a listener here that checks for user input
Button redisplayButton = (Button) V.findViewById(R.id.my_button);
// if the button is clicked....
redisplayButton.setOnClickListener(new OnClickListener() {
public void onClick(View v){
//
// do some stuff
//
// ....then eventually...
displayData(V);
}
});
return V;
}
Later on you can have the displayData() method that defines what the fragment displays....
public void displayData(View V){
// Do something
return;
}
Hope this helps!

Categories

Resources