Frammento All'interno del frammento


137

Ho bisogno di aiuto per quanto riguarda il lavoro sul frammento all'interno del frammento, in realtà sto affrontando un problema nel premere il pulsante Indietro. Schermata principale dell'applicazione ha pulsanti e premendo su ogni vista pulsante si sostituisce con un nuovo frammento (e quel frammento contiene all'interno di un altro frammento), l'aggiunta / sostituzione dinamica del frammento funziona correttamente, premendo il pulsante 1 frammento sostituito, lo stesso accade quando si preme il pulsante, ma se premo il pulsante di nuovo, ha ottenuto un'eccezione:

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

significa che frammento o frammenti interni sono già stati aggiunti e sto cercando di aggiungerli di nuovo, qualcuno ha idea di come lavorare con il frammento all'interno del frammento e di spostarsi avanti e indietro senza alcun problema, grazie per il supporto.

MainActivity, dove i frammenti vengono aggiunti e sostituiti in modo dinamico.

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

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

Spero di aver provato a risolvere il mio problema.


1
sopra il codice funziona perfettamente per me con Android 3.1
Vivek

3
possibile duplicato di Frammenti all'interno di Frammenti
Vladimir

per maggiori dettagli fare riferimento stackoverflow.com/a/11020531/1219456
Raneez Ahmed

Risposte:


284

AFAIK, i frammenti non possono contenere altri frammenti.


AGGIORNARE

Con le versioni correnti del pacchetto di supporto Android - o frammenti nativi a livello di API 17 e successive - puoi nidificare i frammenti, tramite getChildFragmentManager(). Si noti che ciò significa che è necessario utilizzare la versione del pacchetto di supporto Android di frammenti sui livelli API 11-16, perché anche se esiste una versione nativa di frammenti su quei dispositivi, quella versione non ha getChildFragmentManager().


30
La piattaforma fa davvero schifo qui. Ho trascorso tre ore a eseguire il debug di questo perché il frammento interno sarebbe stato reso bene la prima volta, ma sarebbe scomparso dopo una modifica dell'orientamento dello schermo. Nessuna eccezione, informazioni di registro, niente. Passare getChildFragmentManager()e rimuovere setRetainInstance(true)dal frammento interno (peccato) risolto. Grazie per avermi salvato di nuovo la pancetta, @CommonsWare.
Felix,

82

inserisci qui la descrizione dell'immagine

Avevo bisogno di un po 'più di contesto, quindi ho fatto un esempio per mostrare come è fatto. La cosa più utile che ho letto durante la preparazione è stata questa:

Attività

activity_main.xml

Aggiungi a FrameLayoutalla tua attività per contenere il frammento principale.

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

Carica il frammento padre e implementa i listener di frammenti. (Vedi comunicazione frammento .)

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

Frammento genitore

fragment_parent.xml

Aggiungi un altro FrameLayoutcontenitore per il frammento figlio.

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

Utilizzare getChildFragmentManagerin onViewCreatedper impostare il frammento figlio.

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

Frammento di bambino

fragment_child.xml

Non c'è niente di speciale qui.

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

Non c'è niente di troppo speciale qui.

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

Appunti

  • La libreria di supporto viene utilizzata in modo che i frammenti nidificati possano essere utilizzati prima di Android 4.2.


13

I frammenti possono essere aggiunti all'interno di altri frammenti, ma sarà necessario rimuoverlo dal frammento principale ogni volta che onDestroyView()viene chiamato il metodo del frammento principale. E aggiungilo di nuovo nel onCreateView()metodo Parent Fragment .

Fai così:

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

4
Questo non ha funzionato per me. Ho avuto un frammento che ha gonfiato una vista contenente due viste dei bambini. In onActivityCreated()esso sono stati aggiunti due frammenti, uno in ciascuna delle viste, usando getFragmentManager(). Questo ha funzionato per la prima volta, ma alla rotazione e al ripristino era visibile solo uno dei frammenti. getChildFragmentManager()Invece il comportamento era corretto . L'approccio suggerito qui ha gettato un'eccezione poiché l'attività onSaveInstanceState()era già stata chiamata. Il commit della transazione utilizzando ha commitAllowingStateLoss()evitato l'eccezione ma non ha risolto il problema originale.
user1978019,


8

Ho risolto questo problema. È possibile utilizzare la libreria di supporto e ViewPager. Se non è necessario scorrere con il gesto, è possibile disabilitare lo scorrimento. Quindi ecco un po 'di codice per migliorare la mia soluzione:

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È un brutto codice per il test, ma migliora che è possibile.

Il frammento PPS Inside ChildFragmentManagerdeve essere passato aViewPagerAdapter


8

puoi usare la getChildFragmentManager()funzione.

esempio:

Frammento principale:

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

Layout principale ( 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>

Frammento del bambino:

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


    }


} 

4

Non è niente di complicato. Non possiamo usare getFragmentManager()qui. Per usare i frammenti all'interno di un frammento , usiamo getChildFragmentManager(). Il riposo sarà lo stesso.


3

È possibile aggiungere FrameLayoutal frammento e sostituirlo con un altro frammento quando viene inizializzato.

In questo modo, potresti considerare l'altro frammento all'interno del primo frammento.



2

Attualmente nel frammento nidificato, i nidificati sono supportati solo se generati a livello di codice! Quindi in questo momento nessun layout di frammento nidificato è supportato nello schema di layout XML!


1

Ciò può aiutare coloro che lavorano su Kotlin che puoi usare la funzione di estensione, quindi crea un file kotlin diciamo "util.kt" e aggiungi questo pezzo di codice

fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) {

    val transaction = childFragmentManager.beginTransaction()
    transaction.replace(frameId, fragment).commit()
}

Diciamo che questa è la classe del bambino

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

Ora puoi aggiungere i bambini al frammento del padre in questo modo

 FatherPresentation:Fragment()
{
  ...

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

dove R.id.fragmet_field è l'id del layout che conterrà il frammento. Questo lyout è naturalmente all'interno del frammento padre. Ecco un esempio

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>

1

Non c'è supporto per MapFragment, il team di Android afferma che ci sta lavorando da Android 3.0. Qui maggiori informazioni sul problema Ma cosa puoi fare creando un frammento che restituisce a MapActivity. Qui un esempio di codice. Grazie a inazaruk:

Come funziona :

  • MainFragmentActivity è l'attività che estende FragmentActivitye ospita due MapFragments.
  • MyMapActivity estende MapActivity e ha MapView.
  • LocalActivityManagerFragment ospita LocalActivityManager.
  • MyMapFragment si estende LocalActivityManagerFragmente con l'aiuto di TabHostcrea istanza interna di MyMapActivity.

In caso di dubbi, faccelo sapere


0

Ciao, ho risolto questo problema mettendo il frammento in un layout distinto e ho reso visibile solo il layout correlato e reso visibili le altre visioni.

Intendo:

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

Suppongo che aprirai la tua pagina quando si fa clic sul pulsante 1. Puoi controllare la visibilità del tuo frammento sull'azione del clic. Puoi rendere visibile il layout correlato e gli altri spariti e da Fragment Manager puoi prendere il tuo frammento. Questo approccio ha funzionato per me. E poiché la vista che ha visibilità: scomparso è invisibile e non occupa spazio ai fini del layout, penso che questo approccio non causi alcun problema di spazio.

PS: Ho appena provato a spiegare che il mio codice di soluzione potrebbe avere errori di sintassi o struttura incompleta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.