Fragment Inside Fragment

141

Saya butuh bantuan terkait pengerjaan fragmen di dalam fragmen, sebenarnya saya menghadapi masalah saat menekan tombol kembali. Aplikasi Layar utama memiliki tombol dan menekan pada setiap tampilan tombol ganti dengan fragmen baru (dan fragmen itu berisi di dalam fragmen lain), secara dinamis menambahkan / mengganti fragmen berfungsi dengan baik, dengan menekan tombol1 fragmen diganti, sama terjadi saat menekan tombol, tetapi jika saya tekan tombol lagi, mendapat pengecualian:

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

Berarti fragmen atau fragmen dalam sudah ditambahkan dan saya mencoba menambahkannya lagi, siapa pun tahu bagaimana bekerja dengan fragmen di dalam fragmen dan bergerak maju mundur tanpa masalah, terima kasih atas dukungannya.

MainActivity, di mana fragmen ditambahkan dan diganti secara dinamis.

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

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

Harap saya mencoba untuk menyelesaikan masalah saya.

Ijaz Ahmed
sumber
1
kode di atas bekerja dengan baik untuk saya dengan android 3.1
Vivek
3
kemungkinan duplikat Fragmen dalam Fragmen
Vladimir
untuk lebih jelasnya lihat stackoverflow.com/a/11020531/1219456
Raneez Ahmed

Jawaban:

287

AFAIK, fragmen tidak bisa menampung fragmen lain.


MEMPERBARUI

Dengan versi terbaru dari paket Dukungan Android - atau fragmen asli pada API Level 17 dan yang lebih tinggi - Anda bisa menyarangkan fragmen, melalui getChildFragmentManager(). Perhatikan bahwa ini berarti Anda perlu menggunakan versi fragmen paket Dukungan Android pada API Level 11-16, karena meskipun ada versi asli fragmen pada perangkat tersebut, versi tersebut tidak memilikinya getChildFragmentManager().

CommonsWare
sumber
31
Platformnya benar-benar payah di sini. Saya menghabiskan tiga jam men-debug ini karena fragmen bagian dalam akan baik-baik saja pada kali pertama, tetapi akan hilang setelah orientasi layar berubah. Tidak terkecuali, info log, tidak ada. Beralih ke getChildFragmentManager()dan menghapus setRetainInstance(true)dari bagian dalam (kasihan) memperbaikinya. Terima kasih telah menyimpan daging saya lagi, @CommonsWare.
Felix
87

masukkan deskripsi gambar di sini

Saya membutuhkan lebih banyak konteks, jadi saya membuat contoh untuk menunjukkan bagaimana ini dilakukan. Hal paling berguna yang saya baca saat mempersiapkan adalah ini:

Aktivitas

activity_main.xml

Tambahkan a FrameLayoutke aktivitas Anda untuk menampung fragmen induk.

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

Muat fragmen induk dan implementasikan pemroses fragmen. (Lihat komunikasi fragmen .)

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

Fragmen Induk

fragment_parent.xml

Tambahkan FrameLayoutwadah lain untuk fragmen anak.

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

Gunakan getChildFragmentManagerdi onViewCreateduntuk mengatur fragmen anak.

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

Fragmen Anak

fragment_child.xml

Tidak ada yang spesial disini.

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

Tidak ada yang terlalu istimewa di sini.

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

Catatan

  • Pustaka dukungan digunakan agar fragmen bersarang bisa digunakan sebelum Android 4.2.
Suragch
sumber
Ketika saya mencoba menavigasi ke fragmen yang berbeda dari ParentFragment, tidak apa-apa, lalu saya kembali ke ParentFragment dan saya mendapatkan pengecualian: java.lang.IllegalStateException: Anak yang ditentukan sudah memiliki induk. Anda harus memanggil removeView () pada induk anak terlebih dahulu.
Rondev
13

Fragmen dapat ditambahkan ke dalam fragmen lain, tetapi Anda harus menghapusnya dari Fragmen induk setiap kali onDestroyView()metode fragmen induk dipanggil. Dan tambahkan lagi dalam onCreateView()metode Parent Fragment .

Lakukan saja seperti ini:

@Override
    public void onDestroyView()
    {
                FragmentManager mFragmentMgr= getFragmentManager();
        FragmentTransaction mTransaction = mFragmentMgr.beginTransaction();
                Fragment childFragment =mFragmentMgr.findFragmentByTag("qa_fragment")
        mTransaction.remove(childFragment);
        mTransaction.commit();
        super.onDestroyView();
    }
Napolean
sumber
4
Ini tidak berhasil untuk saya. Saya memiliki fragmen yang memperbesar tampilan yang berisi dua tampilan anak. Di onActivityCreated()dalamnya ditambahkan dua fragmen, satu ke masing-masing tampilan, menggunakan getFragmentManager(). Ini berhasil pertama kali, tetapi pada rotasi dan resume hanya satu fragmen yang terlihat. getChildFragmentManager()Sebaliknya, perilaku benar . Pendekatan yang disarankan di sini memberikan pengecualian karena aktivitas onSaveInstanceState()sudah dipanggil. Melakukan transaksi menggunakan commitAllowingStateLoss()menghindari pengecualian tetapi tidak menyelesaikan masalah asli.
user1978019
ada ide tentang stackoverflow.com/questions/63052712/…
Sunil Chaudhary
9

Saya memecahkan masalah ini. Anda dapat menggunakan pustaka Dukungan dan ViewPager. Jika Anda tidak perlu menggesek dengan gerakan, Anda dapat menonaktifkan gesekan. Jadi inilah beberapa kode untuk meningkatkan solusi saya:

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 Ini adalah kode yang jelek untuk pengujian, tetapi itu meningkatkan bahwa itu mungkin.

Fragmen PPS Inside ChildFragmentManagerharus diteruskan keViewPagerAdapter

Vetalll
sumber
8

Anda dapat menggunakan getChildFragmentManager()fungsi.

contoh:

Fragmen induk:

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

Tata letak induk ( 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>

Fragmen Anak:

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


    }


} 
S.M_Emamian
sumber
4

Tidak ada yang rumit. Kami tidak bisa menggunakan di getFragmentManager()sini. Untuk menggunakan Fragmen di dalam Fragmen , kami menggunakan getChildFragmentManager(). Istirahat akan sama.

Wijay Sharma
sumber
3

Anda dapat menambahkan FrameLayoutke fragmen dan menggantinya dengan fragmen lain saat inisialisasi.

Dengan cara ini, Anda dapat menganggap fragmen lain berada di dalam fragmen pertama.

LoveBigPizza
sumber
2

Saat ini dalam fragmen bersarang, yang bertingkat hanya didukung jika dibuat secara terprogram! Jadi saat ini tidak ada layout fragmen bersarang yang didukung dalam skema layout xml!

Andrea Bellitto
sumber
1

Itu dapat membantu mereka yang bekerja di Kotlin, Anda dapat menggunakan fungsi ekstensi jadi buat file kotlin, katakanlah "util.kt" dan tambahkan bagian kode ini

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

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

Katakanlah ini adalah kelas anak

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

Sekarang Anda dapat menambahkan anak-anak ke fragmen ayah seperti ini

 FatherPresentation:Fragment()
{
  ...

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

di mana R.id.fragmet_field adalah id tata letak yang akan berisi fragmen. Lyout ini tentu saja ada di dalam fragmen ayah. Berikut ini contohnya

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>
DINA TAKLIT
sumber
1

Tidak ada dukungan untuk MapFragment, kata tim Android sedang mengerjakannya sejak Android 3.0. Di sini informasi lebih lanjut tentang masalah Tapi apa yang dapat Anda lakukan dengan membuat Fragmen yang mengembalikan file MapActivity. Berikut adalah contoh kode. Berkat inazaruk:

Bagaimana itu bekerja :

  • MainFragmentActivity adalah aktivitas yang memperluas FragmentActivitydan menghosting dua MapFragments.
  • MyMapActivity memperluas MapActivity dan memiliki MapView.
  • LocalActivityManagerFragment host LocalActivityManager.
  • MyMapFragment meluas LocalActivityManagerFragmentdan dengan bantuan TabHostmembuat instance internal MyMapActivity.

Jika Anda ragu, beri tahu saya

reli
sumber
0

Hai, saya memecahkan masalah ini dengan meletakkan per Fragmen ke dalam tata letak yang berbeda. Dan saya hanya membuat Tata Letak terkait terlihat dan membuat visibilitas yang lain hilang.

Maksudku:

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

Saya berasumsi bahwa Anda akan membuka halaman Anda saat tombol 1 diklik. Anda dapat mengontrol visibilitas fragmen Anda pada tindakan klik. Anda dapat membuat Layout terkait terlihat dan yang lainnya hilang dan dengan Manajer Fragmen Anda dapat mengambil fragmen. Pendekatan ini berhasil untuk saya. Dan karena tampilan yang memiliki visibilitas: hilang tidak terlihat, dan tidak membutuhkan ruang untuk tujuan tata letak, saya pikir pendekatan ini tidak menyebabkan masalah ruang.

PS: Saya baru saja mencoba menjelaskan kode solusi saya mungkin memiliki kesalahan sintaks atau struktur yang tidak lengkap.

Sevil
sumber