Im currently working on a sample app that will be using fragments, but im having a little problem regarding changing the fragment.
My default layout for my fragment is fragmentOne (see code below).
<fragment
android:id="#+id/fplace"
android:layout_width="match_parent"
android:layout_height="498dp"
android:name="layout.FragmentOne"
tools:layout="#layout/fragment_fragment_one" />
and that's working correctly.
but when im changing the fragment it appends. the behavior must replace the fragment not append.
here is my code for the activity (see code below).
public void onClick(View view) {
Button button = (Button) view;
Fragment fragment = null;
switch (button.getId()) {
case R.id.f1:
fragment = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fplace, fragment);
ft.commit();
break;
case R.id.f2:
fragment = new FragmentTwo();
fm = getFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.fplace, fragment);
ft.commit();
break;
}
}
and from the fragment one i am loading the data from the onCreateView() which is working correctly. the main problem is the fragment appends not replace.
(see photo below)
the red and yellow must be replaced by the blue colored fragment
As Mike said in comment
You cannot remove/replace Fragments that are declared in your layout.
So here is solution for you. Instead of fragment in xml use framelayout as container which will hold the fragment
use this instead of fragment in xml
<FrameLayout
android:id="#+id/fplace"
android:layout_width="match_parent"
android:layout_height="498dp"
/>
Hope this will help you.
declare a new fragmenttransaction in the second case dont use the fragment transaction that is used in the first case
I have a button inside my Activity and when I click on this button I want to call a Fragment.
For example if I want to call an Activity I can use the intent but if I want to call a Fragment, how can I do that?
I have checked other questions but I have not found an answer to what I'm asking.
btnHome.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
What am I going to put inside this?
You can add your fragment dynamically.You want to create a fragment.
To programmatically add or remove a Fragment, you will need the FragmentManager and FragmentTransaction
XML 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="vertical" >
<FrameLayout
android:id="#+id/myFrame" <!-- Id which you're gonna use in Java -->
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me" />
</LinearLayout>
Java
btnHome.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fragmentManager = getFragmentManager ();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction ();
MyFragment myfragment = new MyFragment(); //your fragment
// work here to add, remove, etc
fragmentTransaction.add (R.id.myFrame, myfragment);
fragmentTransaction.commit ();
}
});
See this doc
You cannot open new fragments. Fragments need to be always hosted by an activity. If the fragment is in the same activity (eg tabs) then the back key navigation is going to be tricky I am assuming that you want to open a new screen with that fragment.
So you would simply create a new activity and put the new fragment in there. That activity would then react to the intent either explicitly via the activity class or implicitly via intent filters.
The answer to your problem is easy: replace the current Fragment with the new Fragment and push transaction onto the backstack. This preserves back button behaviour...
Creating a new Activity really defeats the whole purpose to use fragments anyway...very counter productive.
#Override
public void onClick(View v) {
// Create new fragment and transaction
Fragment newFragment = new chartsFragment();
// consider using Java coding conventions (upper first char class names!!!)
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
https://developer.android.com/guide/components/fragments.html#Transactions
Quotation
I have a Main Menu and created a fragment and its layout.
Now I can't seems to start fragment when user presses a button on main menu.
main menu has its own layout.
now is there anyway i could initialize it from a button?
Button bt = (Button)findViewById(R.id.button1);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainMenu.this, ExercisesFragment.class));
}
});
}
I tried it by this but it gives error saying
Fragment cannot be cast to android.app.Activity
You add fragments using fragment manager:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExercisesFragment fragment = new ExercisesFragment();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
read more on fragments, start here:
http://developer.android.com/guide/components/fragments.html
FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
ft.add(R.id.main_fragment, your_fragment);
ft.addToBackStack("ifneeded");
ft.commit();
You are doing it wrong! Intents are not used to load a fragment.
Solution is to use fragment transactions
to dynamically load the fragment you wish to bring into focus.
Here is what you need to do:
Have a container for the fragment inside the layout of you activity
Example: Assuming the layout resource of my activity is activity_main.xml, I would have a container like so
Follow this guide to create a Fragment
Assuming you already have a fragment setup with name AbcFragment, use fragment transactions to load the fragment into the container that you just created, whenever the user clicks on the button:
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment-container, new AbcFragment)
.commit();
}
});
I tried making a navigation between fragments. I've got the NewFragment.java with the new fragment working. My problem is:
How do I make this onClickListener run NewFragment.java correctly?
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getActivity(), NewFragment.class);
startActivity(i);
}
});
FYI: This is from inside a fragment (I don't know if that matters).
Add following code in your click listener function,
NextFragment nextFrag= new NextFragment();
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.Layout_container, nextFrag, "findThisFragment")
.addToBackStack(null)
.commit();
The string "findThisFragment" can be used to find the fragment later, if you need.
This is more described code of #Narendra's code,
First you need an instance of the 2nd fragment. Then you should have objects of FragmentManager and FragmentTransaction. The complete code is as below,
Fragment2 fragment2=new Fragment2();
FragmentManager fragmentManager=getActivity().getFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_main,fragment2,"tag");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Hope this will work. In case you use androidx, you need getSupportFragmentManager() instead of getFragmentManager().
You should create a function inside activity to open new fragment and pass the activity reference to the fragment and on some event inside fragment call this function.
Use this,
AppCompatActivity activity = (AppCompatActivity) view.getContext();
Fragment myFragment = new MyFragment();
activity.getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, myFragment).addToBackStack(null).commit();
#Override
public void onListItemClick(ListView l, View v, int pos, long id) {
super.onListItemClick(l, v, pos, id);
UserResult nextFrag= new UserResult();
this.getFragmentManager().beginTransaction()
.replace(R.id.content_frame, nextFrag, null)
.addToBackStack(null)
.commit();
}
Using Kotlin to replace a Fragment with another to the container , you can do
button.setOnClickListener {
activity!!
.supportFragmentManager
.beginTransaction()
.replace(R.id.container, NewFragment.newInstance())
.commitNow()
}
use this in adapter/fragment all previous methouds are expired now
((AppCompatActivity) context).getSupportFragmentManager().beginTransaction().replace(R.id.container,new cartFragment()).commit();
a simple option is to navigate to the second fragment by defining an action in the nav_graph.xml and then use it like this (example for Kotlin):
rootViewOfFirstFragment.someBtn.setOnClickListener{
Navigation.findNavController(rootViewOfFirstFragment)
.navigate(R.id.action_firstFragment_to_secondFragment)
}
My how things do change in 8 years time. If you are using NavigationController in your app this is very simple. In your mobile_navigation.xml file you need to create "from" and "to" fragments. In the "from" fragment add the destination id of the "to" fragment.
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="#+id/mobile_navigation"
app:startDestination="#+id/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="com.yourpackage.FromFragment"
android:label="#string/menu_home"
tools:layout="#layout/from_fragment" >
<action android:id="#+id/action_go"
app:destination="#id/dest_fragment"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_pop_enter_anim"
app:popExitAnim="#anim/nav_default_pop_exit_anim"/>
</fragment>
<fragment
android:id="#+id/dest_fragment"
android:name="com.yourpackage.ToFragment"
android:label="To Fragment"
tools:layout="#layout/to_fragment" />
</navigation>
Then in your onClick handler call:
Navigation.findNavController(view).navigate(R.id.action_go);
This page provides more details including how to set up the destination programmatically.
https://developer.android.com/guide/navigation/navigation-navigate
Fragment fr = new Fragment_class();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.viewpagerId, fr);
fragmentTransaction.commit();
Just to be precise, R.id.viewpagerId is cretaed in your current class layout, upon calling, the new fragment automatically gets infiltrated.
Adding to #Narendra solution...
IMPORTANT: When working with fragments, navigations is closely related to host acivity so, you can't justo jump from fragment to fragment without implement that fragment class in host Activity.
Sample:
public class MyHostActivity extends AppCompatActivity implements MyFragmentOne.OnFragmentInteractionListener {
Also, check your host activity has the next override function:
#Override
public void onFragmentInteraction(Uri uri) {}
Hope this helps...
Well my problem was that i used the code from the answer, which is checked as a solution here, but after the replacement was executed, the first layer was still visible and functionating under just opened fragment. My solution was simmple, i added
.remove(CourseListFragment.this)
the CourseListFragment is a class file for the fragment i tried to close.
(MainActivity.java, but for specific section (navigation drawer fragment), if it makes more sense to you)
so my code looks like this now :
LecturesFragment nextFrag= new LecturesFragment();
getActivity().getSupportFragmentManager().beginTransaction()
.remove(CourseListFragment.this)
.replace(((ViewGroup)getView().getParent()).getId(), nextFrag, "findThisFragment")
.addToBackStack(null)
.commit();
And it works like a charm for me.
first of all, give set an ID for your Fragment layout e.g:
<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"
**android:id="#+id/cameraFragment"**
tools:context=".CameraFragment">
and use that ID to replace the view with another fragment.java file. e.g
ivGallary.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UploadDoc uploadDoc= new UploadDoc();
(getActivity()).getSupportFragmentManager().beginTransaction()
.replace(**R.id.cameraFragment**, uploadDoc, "findThisFragment")
.addToBackStack(null)
.commit();
}
});
For Kotlin simply you can use this,
First: Create new instance of the fragment
val newFragment = NewFragment.newInstance()
Second: Start the fragment transaction
val fragmentTransaction: FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()
Third: Replace current fragment with new fragment
( tips: avoid using id of the container view like R.id.fl_fragment, you may face view not find error, just use is at mentioned below)
fragmentTransaction.replace(
(view!!.parent as ViewGroup).id,newFragment
)
Final Steps:
fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
I'm using tabHost in my application but in one of the views (corresponding to one of the tabs) I have a button that have to take me to another activity and then another layout. The question is: how do I get this new layout can continue to have access to the tabs? or better say, How do I load this new layout inside the FrameLayout ?.
Here I have uploaded what I'm trying to do: http://imageshack.us/photo/my-images/541/exampleu.png/
Thanks in advance.!
Pd: I'm new in Android, maybe is there a better way to achieve my purpouse without using TabActivity. I'm open to any suggestion.
EDITED: so I decided to use Fragments as I was suggested. And now I have the following:
AplicationActivity extends FragmentActivity
ClientActivity extends Fragment
SettingsActivity extends Fragment
DataClientActivity extends Fragment
and the following layouts:
activity_aplicacion
activity_client
activity_settings
activity_data_client
The activity_aplicacion.xml has TabHost, FrameLayout and TabWidget and from these I can go to ClientActivity and SettingsActivity using tabs.
In ClientActivity I have a button called "new" and when I press this button I want to go to
DataClientActivity. So, in ClientActivity I have te following:
public void onClickNew(View view){
DataClientActivity fragmentDataClient = new DataClientActivity ();
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.tabcontent,fragmentDataClient , "fragmentDataClient ");
ft.addToBackStack(null);
ft.commit();
}
But when I run my app, I got the folling error:
05-04 21:55:04.780: E/AndroidRuntime(7515): java.lang.IllegalStateException: Could not find a method onClickNew(View) in the activity class com.n.r.AplicationActivity for onClick handler on view class android.widget.Button with id 'buttonNew'
So I'm a little confuse rigth now. Why should I have the onClickNew method in AplicationActivity and not in ClientActivity where I have the button?
EDITED 2: I found the solution for this:
public class ClientActivity extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.activity_clientes, container, false);
**// Register for the Button.OnClick event
Button b = (Button)view.findViewById(R.id.buttonNew);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Toast.makeText(Tab1Fragment.this.getActivity(), "OnClickMe button clicked", Toast.LENGTH_LONG).show();
Log.e("onClickNuevo2 ", "inicio");
DataClientActivity fragmentDataClient= new DataClientActivity();
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.tabcontent,fragmentDataClient, "fragmentDataClient");
ft.addToBackStack(null);
ft.commit();
}
});**
return view;
}
}
I just needed to register the onClick listener to my button inside my ClientActivity. Now every works perfectly!. Thanks so much Divya Motiwala :) and thanks to this link: http://thepseudocoder.wordpress.com/2011/10/04/android-tabs-the-fragment-way/#comment-410
You can use Fragments instead of activites inside Tab. And on click of button, you can replace existing fragment with a new one like this :
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.realtabcontent,newFrag, "New Fragment");
ft.addToBackStack(null);
ft.commit();
In ft.replace 1st parameter is the frameLayout to which fragment is to be attached, second is the fragment class object to be instatiated and third is the tag name.