tutorial studio navegar fragments fragmentos example entre dinamicos diferencia desde activity abrir android android-fragments android-nested-fragment

navegar - fragments dinamicos android studio



Fragmento dentro del fragmento (13)

Necesito ayuda con respecto al trabajo en fragmentos dentro del fragmento, en realidad estoy enfrentando un problema al presionar el botón Atrás. La pantalla principal de la aplicación tiene botones y presionar cada vista de botón reemplazar con un nuevo fragmento (el fragmento contiene dentro de otro fragmento), agregar / reemplazar dinámicamente el fragmento funciona bien, al presionar el botón 1 se reemplaza el fragmento, sucede al presionar el botón, pero si presiono el botón nuevamente, obtuvo una excepción:

"Duplicate id 0x7f05000a, tag null, or parent id 0x7f050009 with another fragment for com........ fragmentname"

significa que fragmento o fragmentos internos ya están agregados y estoy tratando de agregarlos nuevamente, cualquiera tiene idea de cómo trabajar con fragmento dentro de fragmento y moverse hacia adelante y hacia atrás sin ningún problema, gracias por el soporte.

MainActivity, donde los fragmentos se agregan y reemplazan dinámicamente.

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); } }

Aquí está el diseño: 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" <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:id="@+id/linearLayout2" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"></LinearLayout> </LinearLayout>

Espero haber tratado de aclarar mi problema.


¡Curamente en fragmentos anidados, los uno o más anidados solo se admiten si se generan mediante programación! ¡Por lo tanto, en este momento no se admite el diseño de fragmentos anidados en el esquema de diseño xml!


AFAIK, los fragmentos no pueden contener otros fragmentos.

ACTUALIZAR

Con las versiones actuales del paquete de soporte de Android, o fragmentos nativos en API nivel 17 y superior, puede anidar fragmentos, mediante getChildFragmentManager() . Tenga en cuenta que esto significa que necesita utilizar la versión del paquete de soporte de Android de los niveles 11-16 de la API, porque aunque hay una versión nativa de fragmentos en esos dispositivos, esa versión no tiene getChildFragmentManager() .



Eso puede ayudar a los que trabajan en Kotlin a usar la función de extensión así que crea un archivo kotlin digamos "util.kt" y agrega este fragmento de código

fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) { val transaction = childFragmentManager.beginTransaction() transaction.replace(frameId, fragment).commit() }

Digamos que esta es la clase del niño

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) ... } ... }

Ahora puedes agregar a los niños al fragmento de padre como este

FatherPresentation:Fragment() { ... override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val fieldFragment= InputFieldPresentation() addChildFragment(fieldFragment,R.id.fragmet_field) } ... }

donde R.id.fragmet_field es la identificación del diseño que contendrá el fragmento. Esta lyout está dentro del fragmento de padre, por supuesto. Aquí hay un ejemplo

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>


Hola, resolví este problema al poner por Fragmento en un diseño distinto. E hice visible el Diseño relacionado e hice desaparecer las otras visibilidades.

Quiero decir:

<?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>

Asumí que abriría su página al hacer clic en el botón 1. Puede controlar la visibilidad de su fragmento al hacer clic. Puede hacer que el Diseño relacionado sea visible y los demás desaparezcan, y con Fragment Manager puede tomar su fragmento. Este enfoque funcionó para mí. Y dado que la vista que tiene visibilidad: desaparecida es invisible, y no ocupa espacio para propósitos de diseño, creo que este enfoque no causa ningún problema de espacio.

PD: Acabo de intentar explicar que mi código de solución puede tener errores de sintaxis o estructura incompleta.


No es nada complicado. No podemos usar getFragmentManager () aquí. Para usar Fragmentos dentro de un Fragmento, utilizamos getChildFragmentManager (). El resto será lo mismo.


No hay soporte para MapFragment, el equipo de Android dice que está trabajando en eso desde Android 3.0. Aquí encontrará más información sobre el problema http://code.google.com/p/android/issues/detail?id=15347&utm_source=buffer&buffer_share=acc72 Pero lo que puede hacer es crear un Fragmento que devuelva MapActivity. Aquí hay un ejemplo de código. Gracias a inazaruk: https://github.com/inazaruk/examples/tree/master/MapFragmentExample

Cómo funciona:

-MainFragmentActivity es la actividad que extiende FragmentActivity y alberga dos MapFragments. -MyMapActivity extiende MapActivity y tiene MapView. -LocalActivityManagerFragment aloja LocalActivityManager. -MyMapFragment extiende LocalActivityManagerFragment y con la ayuda de TabHost crea una instancia interna de MyMapActivity. si tienes alguna duda, por favor avísame


Puede agregar FrameLayout al fragmento y reemplazarlo con otro fragmento cuando se inicialice.

De esta forma, podrías considerar que el otro fragmento está dentro del primer fragmento.


Resolví este problema. Puede usar la biblioteca de soporte y ViewPager . Si no necesita deslizar con un gesto, puede desactivar deslizar. Así que aquí hay un código para mejorar mi solución:

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; } }

PS: es un código feo para la prueba, pero mejora que es posible.

El fragmento de PPS Inside ChildFragmentManager debe pasar a ViewPagerAdapter


Se pueden agregar fragmentos dentro de otros fragmentos, pero luego deberá eliminarlo del Fragmento padre cada vez que se invoque el método onDestroyView () del fragmento principal. Y añádelo de nuevo en el método OnCreateView () de Parent Fragment.

Simplemente hazlo así:

@Override public void onDestroyView() { FragmentManager mFragmentMgr= getFragmentManager(); FragmentTransaction mTransaction = mFragmentMgr.beginTransaction(); Fragment childFragment =mFragmentMgr.findFragmentByTag("qa_fragment") mTransaction.remove(childFragment); mTransaction.commit(); super.onDestroyView(); }



puede usar la función getChildFragmentManager() .

ejemplo:

Fragmento principal:

@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; }

Diseño principal ( 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>

Fragmento de niño:

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) { } }


Necesitaba un poco más de contexto, así que hice un ejemplo para mostrar cómo se hace esto. Lo más útil que leí durante la preparación fue este:

Actividad

activity_main.xml

Agregue un FrameLayout a su actividad para mantener el fragmento principal.

<?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

Cargue el fragmento principal e implemente los detectores de fragmentos. (Ver comunicación de fragmento )

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"); } }

Fragmento principal

fragment_parent.xml

Agregue otro contenedor FrameLayout para el fragmento hijo.

<?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 en onViewCreated para configurar el fragmento hijo.

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); } }

Fragmento infantil

fragment_child.xml

No hay nada especial aquí.

<?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

No hay nada demasiado especial aquí, tampoco.

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); } }

Notas

  • La biblioteca de soporte se está utilizando para que los fragmentos anidados puedan utilizarse antes de Android 4.2.