Navigate among fragments within one activity - android

I would like to use one Activity which holds several fragments and navigate among the fragments. For example, in the activity, there is a list view which is a fragment, when user select one item from the list, the view will navigate to another fragment, How could this be implemented?
I know there is a nice tutorial on the developer site, but it handles the tablet screen in which two pane layout with one list fragment and one detailed fragment showing in one screen. I only want to navigate among fragments without show two fragments in one screen.
Are there tutorials can teach me how to do it?

In the nutshell the answer to your question is to notify your host activity and then have your host activity replace your current fragment container using FragmentManager.
One of the approach is to make an interface in your first fragment, have your host activity register/listen (implement) to this interface and then have your FragmentManager to replace the container content with the second fragment on listener callback.
I'm not sure about tutorial but here is my snippet:
First Fragment
public class First extends Fragment{
private static onMySignalListener listener;
//call this function from whatever you like i.e button onClickListener
public void switchWindow() {
if(listener != null){
listener.onMySignal();
}
}
public interface onMySignalListener {
//customize this to your liking
//plain without argument
void onMySignal();
//with argument
void onMySignalWithNum(int mNum);
}
public static void setOnMySignalListener(onMySignalListener listener) {
First.listener = listener;
}}
Host Activity
public class HostActivity extends FragmentActivity implements onMySignalListener{
private final String ADD_TAG_IF_NECESSARY = "mTag";
#Override
public void onCreate(Bundle ssi) {
setContentLayout(R.layout.main);
FirstFragment.setOnMySignalListener(this);
}
#Override
public void onMySignal() {
//if you're using compat library
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
//initialize your second fragment
sfragment = SecondFragment.newInstance(null);
//replace your current container being most of the time as FrameLayout
transaction.replace(R.id.container, fragment, ADD_TAG_IF_NECESSARY);
transaction.commit();
}
#Override
public void onMySignalWithNum(int mNum) {
//you can do the same like the above probably with your own customization
}}
This is only an example on how you'd implement interface, kindly tidy it up by yourself. And please be noted though that this is not effective if you have a lot of fragment wanting to notify your host activity about something. doing so will lead you to implement various listener to your host activity.

I think this will be useful for you. It is example of two fragments in one screen works independently.
MainActivity :
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
Fragment newFragment = new Test();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.UprLayout, newFragment);
// transaction.addToBackStack(null);
transaction.commit();
Fragment newFragment2 = new TestRight();
FragmentTransaction transaction2 = getFragmentManager().beginTransaction();
transaction2.add(R.id.dwnLayout, newFragment2);
// transaction.addToBackStack(null);
transaction2.commit();
}
}
main_activity.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/UprLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
<LinearLayout
android:id="#+id/dwnLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
</LinearLayout>
Fragment Test :
public class Test extends Fragment {
TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test, container, false);
return view;
}
}
Fragment TestRight :
public class TestRight extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test_right, container, false);
return view;
}
#Override
public void onStart() {
super.onStart();
Button button = (Button)getActivity().findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Fragment newFragment = new Right2nd();
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction.replace(R.id.dwnLayout, newFragment);
transaction.addToBackStack("aa");
transaction.commit();
//transaction.add(R.id.frag, newFragment).commit();
}
});
}
}
test.xml :
<?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="match_parent"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="test"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="50sp" />
</LinearLayout>
test_right.xml :
<?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="match_parent"
android:gravity="center"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test right"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="45sp" />
</LinearLayout>
Fragment Right2nd :
public class Right2nd extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View vw = inflater.inflate(R.layout.right_2nd, container, false);
return vw;
}
}
right_2nd.xml :
<?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="match_parent"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right 2nd"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="50sp" />
</LinearLayout>

I know this is quite old question but this is currently implemented in Navigation Component https://developer.android.com/guide/navigation/

Here is a very nice tutorial about it. MULTIPLE FRAGMENTS STACK IN EACH VIEWPAGER TAB
I think ChildFragment
would do the job for you. Ignore the Tab ViewPager. It's performing the same thing in multiple tabs. Hope this helps a bit.

Related

How to show fragment only when button pressed?

I'm trying to show an image below a button only after the button has been pressed. My problem is that the fragment is shown immediately when the app is started and not only after the button has been pressed.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void say_hello(View view){
Fragment fragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment2, fragment).commit();
}
}
public class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.news_articles, container, false);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="vertical"
android:layout_height="fill_parent"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center_vertical"
android:text="PRESS THIS"
android:id = "#+id/test_button"
android:background="#drawable/test_button"
android:onClick="say_hello"
/>
<fragment
android:id="#+id/fragment2"
android:name="com.example.tic_tac_toe.ExampleFragment"
android:layout_width="match_parent"
android:layout_height="643dp" />
</LinearLayout>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/cool_dog">
</ImageView>
I'm guessing the fragment shows up when the app is started because of the name I give to the fragment in the XML, but the fragment needs a name otherwise I only get error. How do I get the fragment to display nothing before I have clicked the button?
Instead of using <fragment /> view in your xml, you can use Framelayout and add your fragment to this Framelayout on button click using the following code -
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.mainframe, fragment);
transaction.commit();
Where mainframe is the id of Framelayout.
You can try doing this
android.app.Fragment fragment = getActivity().getFragmentManager().findFragmentByTag("YOUR_FRAGMENT_TAG");
getActivity().getFragmentManager().beginTransaction().hide(fragment);
inside your click event.

fragments overlap in one screen

I am now practicing on ViewPager and Fragments but I am facing an issue with replacing fragment to one another.
It is working well with swiping screen to move to another fragment, but I also wanted to try out if I can do this with a button too.
So I added a button, and tried to use FragmentManager's replace() method.
But what it actually does is not replacing the fragment but adding the fragment on the current fragment.
In a simple word, it overlaps.
Could not really find anything helpful for hours now, can anyone please help me with it?
Here is my code of the fragment that has the button:
public class MainActivity extends Fragment {
Fragment fragment;
FragmentManager fragmentManager;
FragmentTransaction fragmentTransaction;
Button buildButton;
private ViewPager viewPager;
public static Fragment newInstance(Context context) {
MainActivity mainActivity = new MainActivity();
return mainActivity;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.main, null);
return root;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
buildButton = (Button) getView().findViewById(R.id.buildButton);
buildButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fragment = new SecondActivity();
fragmentManager = getActivity().getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.calendarActivity, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
}
}
And this is the xml file of the fragment:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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=".MainActivity">
<fragment class="com.example.auclo.calendarpractice5.MainActivity"
android:id="#+id/calendarActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<Button
android:id="#+id/buildButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:layout_marginEnd="148dp"
android:layout_marginStart="148dp"
android:layout_marginTop="16dp"
android:text="Track"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/calendarView" />
</android.support.constraint.ConstraintLayout>
And this is the fragment that I want to replace to:
public class SecondActivity extends Fragment {
TextView textView;
public static Fragment newInstance(Context context) {
SecondActivity secondActivity = new SecondActivity();
return secondActivity;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.activity_second, null);
return root;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
textView = getView().findViewById(R.id.textView);
}
}
And xml of the second fragment:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".SecondActivity">
<fragment class="com.example.auclo.calendarpractice5.SecondActivity"
android:id="#+id/secondActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pikachu"
android:textSize="18sp" />
</RelativeLayout>
I will really appreciate to any kind of help.
Thank you!
The issue is that you're replacing the element with ID calendarActivity with your new fragment. This element is inside the XML for your first fragment (I think, based on your post). So it's putting this fragment in your old fragment.
You'll need to instead use the id in R.layout.main that represents your first fragment. I usually use a framelayout for this. Then I have the activity replace that framelayout with a fragment in its onCreate().
To add the same visual effects, you have to add a animation to your fragmentTransaction
Exemple:
fragmentTransaction.setCuston(
R.anim.enter_from_right,
R.anim.exit_to_left);
See this answer for explanation on fragments animations

Switching 2 fragments within one activity - Android

I'm trying to replace one fragment with another following a button click (onClick) event. I'm new to fragments so if I'm going about this the wrong way please let me know.
At run time a frame layout (container) is loaded. A fragment is then added to it dynamically. This works fine. If I add in the setOnClickListener I get a NullPointerException. Here's the Java:
public class WelcomeActivity extends ActionBarActivity {
FrameLayout container;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
//setContentView(R.layout.welcome_fragment);
container = (FrameLayout)findViewById(R.id.mainContainer);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.mainContainer) != 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;
}
addWelcomeFragment();
}
//NPE at the below line
Button submitUser = (Button) findViewById(R.id.submitUser);
submitUser.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
addExpedFragment();
}
});
}
Through researching fragments I'm using static class within the WelcomeActivity class to load the fragments. They are here:
public static class WelcomeFragment extends Fragment {
public static Fragment newInstance(){
Fragment wFrag = new WelcomeFragment();
return wFrag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.welcome_fragment, null);
return v;
}
}
//-----------------------------------------------------------------------------------------------------//
public static class ExpedFragment extends Fragment {
public static Fragment secondInstance(){
Fragment eFrag = new ExpedFragment();
return eFrag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.exped_fragment, null);
return v;
}
}
And the methods to invoke these are also with WelcomeActivity here:
private void addWelcomeFragment(){
Fragment welcome = WelcomeFragment.newInstance();
FragmentTransaction fTrans = getSupportFragmentManager().beginTransaction();
fTrans.add(R.id.mainContainer, welcome);
fTrans.addToBackStack(null);
fTrans.commit();
}
private void addExpedFragment(){
Fragment exped = ExpedFragment.secondInstance();
getSupportFragmentManager().beginTransaction().replace(R.id.mainContainer, exped).commit();
}
I have a feeling that the problem is to do with trying to find the button view id "submitUser" from the first fragment. My xmls look like this.
The first empty FrameLayout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
The first fragment loaded in at runtime:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/welcome_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
tools:context=".WelcomeActivity" >
<TextView
android:id="#+id/welcome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/welcome1"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="#+id/userName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/welcome"
android:layout_alignRight="#+id/welcome"
android:layout_below="#+id/welcome"
android:layout_marginTop="32dp"
android:ems="10"
android:hint="#string/userHint"
android:inputType="textPersonName" >
<requestFocus />
</EditText>
<Button
android:id="#+id/submitUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/userName"
android:layout_alignRight="#+id/userName"
android:layout_below="#+id/userName"
android:layout_marginTop="16dp"
android:text="#string/Done" />
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
The second fragment to replace the first with the onClick event:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/exped_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
tools:context=".WelcomeActivity" >
<TextView
android:id="#+id/expedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/exped"
android:textAppearance="?android:attr/textAppearanceLarge">
</TextView>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
IF I forget loading the first fragment at runtime and setContentView(first fragment) there is no NullPointerException but the two fragments overlay each other when the button is pressed rather than replacing.
So my question is, how do I reference the active fragment to properly set the OnClickListener and avoid the NullPointerException?
Button submitUser = (Button) findViewById(R.id.submitUser);
gives the NPE
Problem:
Button submitUser = (Button) findViewById(R.id.submitUser);
The submitUser is located in your WelcomeFragment's layout not in your Activity's layout that is why it is null.
solution:
Instead of initializing it in your activity class you need to initialize it within your Welcome fragment view.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.welcome_fragment, null);
Button submitUser = (Button) v.findViewById(R.id.submitUser);
submitUser.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
addExpedFragment();
}
});
return v;
}
EDIT:
private void addExpedFragment(){
Fragment exped = ExpedFragment.secondInstance();
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainContainer, exped).commit();
}

Custom Adapter within a Nested Fragment

I have a ViewPager which holds multiple base fragments, each base fragment have four more nested fragments and each nested fragment is a combination of 5 imageViews and textView.
(This is what I intended to do)
I have created a sample application but I am not able to implement that properly. I cannot see any view in the nested fragment or the base fragment.
Here's the code for the sample application
main.xml
<?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"
>
<fragment android:name="com.example.nestedfragments.BaseFragment"
android:id="#+id/left_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"/>
</LinearLayout>
MainActivity.java
package com.example.nestedfragments;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
base_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<Button
android:id="#+id/button1"
android:text="Launch Nested Fragment"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingBottom="10dp"/>
</RelativeLayout>
BaseFragment.java
public class BaseFragment extends Fragment {
Button doNestingButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// set the view
View root = inflater.inflate(R.layout.base_fragment, container, false);
doNestingButton = (Button) root.findViewById(R.id.button1);
doNestingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment videoFragment = new NestedFragment();
// we get the 'childFragmentManager' for our transaction
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
// make the back button return to the main screen
// and supply the tag 'left' to the backstack
transaction.addToBackStack("left");
// add our new nested fragment
transaction.add(getId(), videoFragment, "left");
// commit the transaction
transaction.commit();
}
});
return root;
}
}
nested_fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="154dp"
android:layout_height="154dp"
android:id="#+id/imageView" android:layout_gravity="left|center_vertical"
android:src="#drawable/ic_splash"/>
</LinearLayout>
NestedFragment.java
public class NestedFragment extends Fragment {
public NestedFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.nested_fragment, container, false);
ImageView doNestingButton = (ImageView) root.findViewById(R.id.imageView);
return root;
}
Once again this is a sample application, please guide me.
From your above code, you have not used the fragment container layout such as FrameLayout in base_fragment.xml .So add the frame layout for nested fragment inbase_fragment.xml

Fragment Inside Fragment

I need help regarding working on fragment inside fragment, actually I
am facing a problem on pressing back button. Application Main screen
has buttons and pressing on each button view replace with new
fragment(and that fragment contain inside another fragment),
dynamically adding/replacing fragment is working fine, by pressing
button1 fragment replaced, same happens when pressing button, but if
I press the button again, got an exception:
"Duplicate id 0x7f05000a, tag null, or parent id 0x7f050009 with
another fragment for com........ fragmentname"
means fragment or inner fragments are already added and I am trying
to add them again, anybody has idea how to work with fragment inside
fragment and moving back and forth without any problem, thanks for the
support.
MainActivity, where fragments are dynamical added and
replaced.
public class FragmentInsideFragmentTestActivity extends Activity {
private Button button1;
private Button button2;
private Button button3;
private Button button4;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button1 =(Button) this.findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
button2 =(Button) this.findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
button3 =(Button) this.findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
button4 =(Button) this.findViewById(R.id.button4);
button4.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
}
public void onButtonClick(View v) {
Fragment fg;
switch (v.getId()) {
case R.id.button1:
fg=FirstFragment.newInstance();
replaceFragment(fg);
break;
case R.id.button2:
fg=SecondFragment.newInstance();
replaceFragment(fg);
break;
case R.id.button3:
fg=FirstFragment.newInstance();
replaceFragment(fg);
break;
case R.id.button4:
fg=SecondFragment.newInstance();
replaceFragment(fg);
break;
}
}
private void replaceFragment(Fragment newFragment) {
FragmentTransaction trasection = getFragmentManager().beginTransaction();
if(!newFragment.isAdded()) {
try {
//FragmentTransaction trasection =
getFragmentManager().beginTransaction();
trasection.replace(R.id.linearLayout2, newFragment);
trasection.addToBackStack(null);
trasection.commit();
} catch (Exception e) {
// TODO: handle exception
// AppConstants.printLog(e.getMessage());
} else {
trasection.show(newFragment);
}
}
}
Here is Layout: main.xml
<?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">
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="#+id/button2"
android:text="Button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button3"
android:text="Button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button4"
android:text="Button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" />
</LinearLayout>
Hope I tried to clear my problem.
AFAIK, fragments cannot hold other fragments.
UPDATE
With current versions of the Android Support package -- or native fragments on API Level 17 and higher -- you can nest fragments, by means of getChildFragmentManager(). Note that this means that you need to use the Android Support package version of fragments on API Levels 11-16, because even though there is a native version of fragments on those devices, that version does not have getChildFragmentManager().
I needed some more context, so I made an example to show how this is done. The most helpful thing I read while preparing was this:
Creating and Using Fragments
Activity
activity_main.xml
Add a FrameLayout to your activity to hold the parent fragment.
<?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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Activity"/>
<FrameLayout
android:id="#+id/parent_fragment_container"
android:layout_width="match_parent"
android:layout_height="200dp"/>
</LinearLayout>
MainActivity.java
Load the parent fragment and implement the fragment listeners. (See fragment communication.)
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements ParentFragment.OnFragmentInteractionListener, ChildFragment.OnFragmentInteractionListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Begin the transaction
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.parent_fragment_container, new ParentFragment());
ft.commit();
}
#Override
public void messageFromParentFragment(Uri uri) {
Log.i("TAG", "received communication from parent fragment");
}
#Override
public void messageFromChildFragment(Uri uri) {
Log.i("TAG", "received communication from child fragment");
}
}
Parent Fragment
fragment_parent.xml
Add another FrameLayout container for the child fragment.
<?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"
android:layout_margin="20dp"
android:background="#91d0c2">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Parent fragment"/>
<FrameLayout
android:id="#+id/child_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
ParentFragment.java
Use getChildFragmentManager in onViewCreated to set up the child fragment.
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
public class ParentFragment extends Fragment {
private OnFragmentInteractionListener mListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_parent, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Fragment childFragment = new ChildFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.child_fragment_container, childFragment).commit();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void messageFromParentFragment(Uri uri);
}
}
Child Fragment
fragment_child.xml
There is nothing special here.
<?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"
android:layout_margin="20dp"
android:background="#f1ff91">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Child fragment"/>
</LinearLayout>
ChildFragment.java
There is nothing too special here, either.
import android.support.v4.app.Fragment;
public class ChildFragment extends Fragment {
private OnFragmentInteractionListener mListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_child, container, false);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void messageFromChildFragment(Uri uri);
}
}
Notes
The support library is being used so that nested fragments can be used before Android 4.2.
Since Android 4.2 (API 17) nested fragments become available http://developer.android.com/about/versions/android-4.2.html#NestedFragments
To place fragment inside other fragment use getChildFragmentManager()
It also available in support library!
you can use getChildFragmentManager() function.
example:
Parent fragment :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.parent_fragment, container,
false);
}
//child fragment
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
ChildFragment fragB = new ChildFragment ();
childFragTrans.add(R.id.FRAGMENT_PLACEHOLDER, fragB);
childFragTrans.addToBackStack("B");
childFragTrans.commit();
return rootView;
}
Parent layout (parent_fragment.xml):
<?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"
android:background="#android:color/white">
<FrameLayout
android:id="#+id/FRAGMENT_PLACEHOLDER"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Child Fragment:
public class ChildFragment extends Fragment implements View.OnClickListener{
View v ;
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootView = inflater.inflate(R.layout.child_fragment, container, false);
v = rootView;
return rootView;
}
#Override
public void onClick(View view) {
}
}
Fragments can be added inside other fragments but then you will need to remove it from parent Fragment each time when onDestroyView() method of parent fragment is called. And again add it in Parent Fragment's onCreateView() method.
Just do like this :
#Override
public void onDestroyView()
{
FragmentManager mFragmentMgr= getFragmentManager();
FragmentTransaction mTransaction = mFragmentMgr.beginTransaction();
Fragment childFragment =mFragmentMgr.findFragmentByTag("qa_fragment")
mTransaction.remove(childFragment);
mTransaction.commit();
super.onDestroyView();
}
I solved this problem. You can use Support library and ViewPager. If you don't need swiping by gesture you can disable swiping. So here is some code to improve my solution:
public class TestFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag, container, false);
final ArrayList<Fragment> list = new ArrayList<Fragment>();
list.add(new TrFrag());
list.add(new TrFrag());
list.add(new TrFrag());
ViewPager pager = (ViewPager) v.findViewById(R.id.pager);
pager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {
#Override
public Fragment getItem(int i) {
return list.get(i);
}
#Override
public int getCount() {
return list.size();
}
});
return v;
}
}
P.S.It is ugly code for test, but it improves that it is possible.
P.P.S Inside fragment ChildFragmentManager should be passed to ViewPagerAdapter
It's nothing complicated. We cannot use getFragmentManager() here. For using Fragments inside a Fragment, we use getChildFragmentManager(). Rest will be the same.
Use getChildFragmentManager(), follow the link :
Nested Fragment
You can add FrameLayout to the fragment and replace it with another fragment when it initializes.
This way , you could consider the other fragment to be inside the first fragment.
Curently in nested fragment, the nested one(s) are only supported if they are generated programmatically! So at this time no nested fragment layout are supported in xml layout scheme!
That may help those who works on Kotlin you can use extension function
so create a kotlin file let's say "util.kt" and add this piece of code
fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) {
val transaction = childFragmentManager.beginTransaction()
transaction.replace(frameId, fragment).commit()
}
Let's say this is the class of the child
class InputFieldPresentation: Fragment()
{
var views: View? = null
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
views = inflater!!.inflate(R.layout.input_field_frag, container, false)
return views
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
}
...
}
Now you can add the children to the father fragment like this
FatherPresentation:Fragment()
{
...
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val fieldFragment= InputFieldPresentation()
addChildFragment(fieldFragment,R.id.fragmet_field)
}
...
}
where R.id.fragmet_field is the id of the layout which will contain the fragment.This lyout is inside the father fragment of course.
Here is an example
father_fragment.xml:
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
>
...
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:id="#+id/fragmet_field"
android:orientation="vertical"
>
</LinearLayout>
...
</LinearLayout>
There is no support for MapFragment, Android team says is working on it since Android 3.0. Here more information about the issue But what you can do is by creating a Fragment that returns a MapActivity. Here is a code example. Thanks to inazaruk:
How it works:
MainFragmentActivity is the activity that extends FragmentActivity and hosts two MapFragments.
MyMapActivity extends MapActivity and has MapView.
LocalActivityManagerFragment hosts LocalActivityManager.
MyMapFragment extends LocalActivityManagerFragment and with help of TabHost creates internal instance of MyMapActivity.
If you have any doubt please let me know
Hi I solved this problem by putting per Fragment into distinct layout.And I made just related Layout visible and made the others visibilities gone.
I mean:
<?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">
<LinearLayout android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:layout_width="wrap_content"
android:id="#+id/button1"
android:layout_height="wrap_content"
android:text="Button1"></Button>
<Button android:text="Button2"
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<Button android:text="Button3"
android:id="#+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<Button android:text="Button4"
android:id="#+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
</LinearLayout>
<LinearLayout android:layout_width="full_screen"
android:layout_height="0dp"
android:layout_weight="1"
android:id="action_For_Button1"
android:visibility="visible">
<Fragment android:layout_width="full_screen"
android:layout_height="full_screen"
android:id="fragment1"
.
.
.
/ >
</LinearLayout>
<LinearLayout android:layout_width="full_screen"
android:layout_height="0dp"
android:id="action_For_Button1"
android:layout_weight="1"
android:visibility="gone">
<Fragment android:layout_width="full_screen"
android:layout_height="full_screen"
android:id="fragment2"
.
.
.
/ >
</LinearLayout>
.
.
.
</LinearLayout>
I assumed that you will open your page as button 1 is clicked.You can control your fragment's visibilities on click action.You can make related Layout visible and the others gone and by Fragment Manager you can take your fragment.This approach worked for me.And since view that has visibility:gone is invisible, and it doesn't take any space for layout purposes I think this approach does not cause any space problem.
P.S:I just tried to explain my solution code may have syntax mistakes or uncompleted structure.

Categories

Resources