Ambil Fragmen dari ViewPager


248

Saya menggunakan ViewPagerbersama dengan FragmentStatePagerAdapteruntuk meng-host tiga fragmen yang berbeda:

  • [Fragment1]
  • [Fragment2]
  • [Fragment3]

Ketika saya ingin mendapatkan Fragment1dari ViewPagerdalam FragmentActivity.

Apa masalahnya, dan bagaimana cara memperbaikinya?

Jawaban:


504

Jawaban utama bergantung pada nama yang dihasilkan oleh framework. Jika itu pernah berubah, maka itu tidak akan berfungsi lagi.

Bagaimana dengan solusi ini, mengesampingkan instantiateItem()dan destroyItem()dari Anda Fragment(State)PagerAdapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return ...;
    }

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(...); 
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}

Ini sepertinya bekerja untuk saya ketika berhadapan dengan Fragmen yang tersedia. Fragmen yang belum dipakai, akan mengembalikan nol saat menelepon getRegisteredFragment. Tapi saya telah menggunakan ini sebagian besar untuk mendapatkan arus Fragmentkeluar dari ViewPager: adapater.getRegisteredFragment(viewPager.getCurrentItem())dan ini tidak akan kembali null.

Saya tidak mengetahui adanya kelemahan lain dari solusi ini. Jika ada, saya ingin tahu.


41
Ini adalah solusi terbaik yang bisa saya pikirkan juga. Hanya saran akan mungkin membungkus Fragmentdalam WeakReferenceuntuk menjamin Anda tidak mencegah fragmen hancur dari yang sampah yang dikumpulkan? Sepertinya hal yang tepat untuk dilakukan ...
Alex Lockwood

7
Apa yang terjadi ketika MyPagerAdapterdihancurkan karena siklus hidup (yaitu memutar), tidak registerdFragmentsakan hilang? Apakah Activity/ Fragmentmenggunakan MyPagerAdapterharus menyimpannya onSaveInstanceState, dan kemudian perlu memperbaruinya dengan FragmentManagerref baru ?
Steven Byle

10
Jika saya tidak salah (dan Anda harus memeriksa ini), metode getItem tidak disebut - seperti yang Anda tahu - tetapi metode instantiateItem dipanggil untuk setiap Fragmen yang sedang dipulihkan oleh kerangka kerja setelah rotasi.
Streets Of Boston

6
Ya saya telah memverifikasi bahwa getItemtidak dipanggil lagi pada rotate (untuk setiap fragmen yang sudah dibuat), karena FragmentManagermengembalikan status yang Fragmentsdipegangnya dalam pager. Jika instantiateItemdipanggil ketika masing Fragment- masing dipulihkan, maka solusi ini sebenarnya lebih aman dan lebih banyak bukti di masa depan daripada milik saya atau jawaban yang diterima. Saya akan mempertimbangkan untuk mencoba ini sendiri.
Steven Byle

6
@Dori saya tidak merusaknya. Solusi saya tidak menggunakan hasil dari panggilan 'getItem ()'. Alih-alih, ia menggunakan hasil yang disimpan dari panggilan 'instantiateItem ()'. Dan siklus hidup fragmen tidak rusak, karena fragmen yang disimpan akan dihapus dari array-jarang pada panggilan 'destroyItem ()'.
Streets Of Boston

85

Untuk mengambil fragmen dari ViewPager ada banyak jawaban di sini dan di utas / blog SO terkait lainnya. Semua orang yang saya lihat rusak, dan mereka umumnya tampak jatuh ke dalam salah satu dari dua jenis yang tercantum di bawah ini. Ada beberapa solusi yang valid lain jika Anda hanya ingin mengambil fragmen saat ini, seperti ini jawaban lain di thread ini.

Jika menggunakan FragmentPagerAdapterlihat di bawah. Jika menggunakan FragmentStatePagerAdapternilainya melihat ini . Indeks ambil yang bukan yang sekarang di FragmentStateAdapter tidak berguna karena pada dasarnya ini akan sepenuhnya dihancurkan keluar dari tampilan / keluar dari batas offScreenLimit.

JALAN YANG TIDAK SELAMAT

Salah: Pertahankan daftar fragmen internal Anda sendiri, ditambahkan ke saat FragmentPagerAdapter.getItem()dipanggil

  • Biasanya menggunakan a SparseArrayatauMap
  • Bukan salah satu dari banyak contoh yang saya lihat yang menjelaskan peristiwa siklus hidup sehingga solusi ini rapuh. Seperti getItemyang disebut pertama kali halaman digulir ke (atau diperoleh jika Anda ViewPager.setOffscreenPageLimit(x)> 0) di ViewPager, jika hosting Activity/ Fragmentterbunuh atau dimulai ulang maka internal SpaseArrayakan dihapus ketika kustom FragmentPagerActivity dibuat ulang, tetapi di belakang layar, ViewPagers fragmen internal yang akan diciptakan, dan getItemakan tidak dipanggil untuk salah satu indeks, sehingga kemampuan untuk mendapatkan fragmen dari indeks akan hilang selamanya. Anda dapat menjelaskan ini dengan menyimpan dan mengembalikan referensi fragmen ini melalui FragmentManager.getFragment()dan putFragmenttetapi ini mulai mendapatkan IMHO berantakan.

Salah: Bangun id tag Anda sendiri sesuai dengan apa yang digunakan di bawah kapFragmentPagerAdapter dan gunakan ini untuk mengambil fragmen halaman dariFragmentManager

  • Ini jauh lebih baik karena mengatasi masalah kehilangan-fragmen-referensi dalam solusi internal-array pertama, tetapi sebagaimana ditunjukkan dalam jawaban di atas dan di tempat lain di internet - rasanya berantakan karena ini adalah metode privat internal ViewPageryang dapat berubah kapan saja atau untuk versi OS apa pun.

Metode yang diciptakan untuk solusi ini adalah

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

PATH SELAMAT: ViewPager.instantiateItem()

Pendekatan yang mirip dengan di getItem()atas tetapi tidak merusak siklus adalah untuk ini adalah untuk menghubungkan ke instantiateItem()bukan getItem()sebagai yang pertama akan dipanggil setiap kali indeks dibuat / diakses. Lihat jawaban ini

JALAN SELAMAT: Bangun sendiri FragmentViewPager

Buat FragmentViewPagerkelas Anda sendiri dari sumber lib dukungan terbaru dan ubah metode yang digunakan secara internal untuk membuat tag fragmen. Anda bisa menggantinya dengan yang di bawah ini. Ini memiliki keuntungan bahwa Anda tahu pembuatan tag tidak akan pernah berubah dan Anda tidak mengandalkan api / metode pribadi, yang selalu berbahaya.

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

Kemudian seperti yang dikatakan oleh doc, ketika Anda ingin mengambil sebuah fragmen yang digunakan untuk indeks, panggil saja sesuatu seperti metode ini (yang dapat Anda masukkan ke dalam custom FragmentPagerAdapteratau subclass) karena menyadari hasilnya mungkin nol jika getItem belum dipanggil untuk yaitu halaman itu belum dibuat.

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

Ini adalah solusi sederhana dan menyelesaikan masalah di dua solusi lain yang ditemukan di mana-mana di web


6
Ini akan berhasil, tetapi itu perlu menyalin kelas ViewPager ke kode sumber Anda sendiri. Mengandalkan 'instantiateItem ()' dan 'destroyItem ()' dari pager-adapter ViewPager akan bekerja dan akan menghormati siklus hidup fragmen (2 metode ini disebut juga ketika fragmen dibuat dari keadaan-instance-save). Anda benar, yang mengandalkan 'getItem ()' yang dipanggil bukan ide yang baik dan tidak menggunakan API pribadi.
Streets Of Boston

+1 saya setuju itu juga solusi dan telah diedit di atas. Satu-satunya perbedaan adalah bahwa hal-hal di atas berfungsi dalam satu kasus penggunaan sekali lagi yang instantiateItem()mana adalah ketika Anda ingin mengakses sebuah fragmen yang belum dikunjungi setelah peristiwa siklus hidup telah terjadi dan dikunjungi sebelum acara siklus hidup. Perbedaan kecil yang saya tahu tetapi salah satu yang menyebabkan bug halus dalam program saya maka saya mencari tahu ini.
Dori

Jika setOffscreenPageLimit = 1 (default), FragmentStatePageAdapter akan mulai menukar fragmen masuk dan keluar dari memori saat halaman tampilan diakses. Dengan panggilan ke getItem () instance baru dari halaman / fragmen yang telah ditinjau kembali akan dibuat. Setelah ditinjau kembali, apakah ada cara untuk menginstruksikan sistem untuk melanjutkan contoh yang dibuat sebelumnya, daripada membuat yang baru?
carl

jika di luar batas halaman itu harus membuat yang baru - tetapi melewati dalam kondisi tersimpan. Jika ingin mempertahankan yang lama di sekitar maka Anda dapat meningkatkan batas halaman
Dori

@Dori tidak ada getItemId(pos)di dalamFragmentStatePagerAdapter
Jemshit Iskenderov

70

Tambahkan metode selanjutnya ke FragmentPagerAdapter Anda:

public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return  mFragmentManager.findFragmentByTag(name);
}

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

getActiveFragment (0) harus berfungsi.

Berikut adalah solusi yang diimplementasikan ke dalam ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Jika sesuatu gagal, Anda akan melihat log kerusakan yang bagus.


Terima kasih banyak:) . Melalui saya sovled dengan cara lain yang saya gunakan pawang untuk mengirim fragmen. Ini tidak terlalu cocok tetapi akhirnya menyisihkan masalah. Ngomong-ngomong, kau baik-baik saja :)
Qun Qin

12
Saya menggunakan metode ini, tapi saya yakin itu berhenti berfungsi ketika saya pindah ke API 17 (?). Saya akan merekomendasikan metode lain, dan lebih suka jika Google hanya menerbitkan API untuk mengambil Fragmen dari ViewPager, mengingat posisinya.
gcl1

saya punya masalah dengan memanggil fragmen kedua, metode membuat yang baru
Vasil Valchev

2
Karena beberapa metode makeFragmentName versi API diubah menjadi String statis makeFragmentName privat (int viewId, id panjang) {return "android: switcher:" + viewId + ":" + id; } jadi metode getActiveFragment sekarang akan terlihat seperti ini (gunakan getItemId alih-alih posisi untuk argumen kedua) public Fragment getActiveFragment (wadah ViewPager, posisi int) {String name = makeFragmentName (container.getId (), getItemId (posisi)); return mFragmentManager.findFragmentByTag (nama); }
Eugene Popovich

1
Ini benar-benar bekerja tetapi itu benar-benar berbahaya karena ia meneruskan implementasi pager tampilan dalam dan jika google akan mengubah implementasi (dan mereka dapat) hal-hal buruk akan terjadi. Saya sangat berharap goole akan membuatnya tersedia untuk mendapatkan fragmen live
shem

38

Solusi sederhana lain:

    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }

1
Ini sepertinya sempurna untuk kebutuhan fragmen saya saat ini.
danny117

Jika semua yang perlu Anda lakukan adalah mendapatkan Fragmen yang dipilih saat ini, ini yang Anda butuhkan - metode setPrimaryItem diatur pada lampiran dan juga pada setiap pembaruan ke set internal Fragmen sebagai item saat ini.
Graeme

1
Ini terdengar seperti solusi yang bagus tetapi seperti setPrimaryItem()yang disebut setelah ViewPager.OnPageChangeListener#onPageSelected() saya tidak dapat menggunakannya :-(
hardysim

21

Saya tahu ini memiliki beberapa jawaban, tetapi mungkin ini akan membantu seseorang. Saya telah menggunakan solusi yang relatif sederhana ketika saya perlu mendapatkan Fragmentdari saya ViewPager. Di Activityatau Fragmentmemegang ViewPager, Anda dapat menggunakan kode ini untuk menggilir setiap Fragmentmemegangnya.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
    if(viewPagerFragment != null) {
        // Do something with your Fragment
        // Check viewPagerFragment.isResumed() if you intend on interacting with any views.
    }
}
  • Jika Anda tahu posisi Anda Fragmentdi ViewPager, Anda bisa menelepon getItem(knownPosition).

  • Jika Anda tidak tahu posisi Anda Fragmentdi ViewPager, Anda dapat meminta anak-anak Anda Fragmentsmengimplementasikan antarmuka dengan metode seperti getUniqueId(), dan menggunakannya untuk membedakan mereka. Atau Anda dapat menelusuri semua Fragmentsdan memeriksa jenis kelas, sepertiif(viewPagerFragment instanceof FragmentClassYouWant)

!!! Sunting !!!

Saya telah menemukan bahwa getItemhanya dipanggil oleh FragmentPagerAdapterketika masing-masing Fragmentperlu dibuat pertama kali , setelah itu, tampaknya Fragmentsyang didaur ulang menggunakan FragmentManager. Dengan cara ini, banyak implementasi FragmentPagerAdapterbuat baru Fragment di getItem. Menggunakan metode saya di atas, ini berarti kita akan membuat yang baru Fragmentsetiap kali getItemdipanggil saat kita menelusuri semua item dalam FragmentPagerAdapter. Karena ini, saya telah menemukan pendekatan yang lebih baik, menggunakan FragmentManageruntuk mendapatkan masing-masing Fragmentsebagai gantinya (menggunakan jawaban yang diterima). Ini adalah solusi yang lebih lengkap, dan telah bekerja dengan baik untuk saya.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    String name = makeFragmentName(mViewPager.getId(), i);
    Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
    // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
    if(viewPagerFragment != null) {

        // Do something with your Fragment
        if (viewPagerFragment.isResumed()) {
            // Interact with any views/data that must be alive
        }
        else {
            // Flag something for update later, when this viewPagerFragment
            // returns to onResume
        }
    }
}

Dan Anda akan membutuhkan metode ini.

private static String makeFragmentName(int viewId, int position) {
    return "android:switcher:" + viewId + ":" + position;
}

1
Anda baru saja menemukanFragmentByTag (), tetapi di mana kita dapat mengatur TAG dengan fragmen ??
VinceStyling

@ karena ViewPageritu sendiri yang mengatur tag tersebut. Solusi ini rapuh karena bergantung pada mengetahui konvensi penamaan "tersembunyi" dari ViewPager. Jawaban Streets of Boston adalah solusi yang jauh lebih komprehensif, yang sekarang saya gunakan dalam proyek saya (bukan pendekatan ini).
Steven Byle

Ini sangat bagus! Tapi saya menghapus persyaratan "if (viewPagerFragment.isResumed ())" karena saya perlu memperbarui halaman ListFragment saya yang tidak ditampilkan di layar. Kemudian ketika pengguna kembali ke halaman ListFragment, semuanya diperbarui dengan data baru.
JDJ

10

Untuk kasus saya, tidak ada solusi di atas yang berfungsi.

Namun karena saya menggunakan Child Fragment Manager di Fragmen, berikut ini digunakan:

Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());

Ini hanya akan berfungsi jika fragmen Anda di Manajer sesuai dengan item viewpager.


Ini adalah jawaban sempurna untuk mendapatkan fragmen lama dari pager tampilan saat aktivitas atau fragmen dibuat kembali.
Smeet

7

Untuk mendapatkan fragmen yang terlihat saat ini dari ViewPager . Saya menggunakan pernyataan sederhana ini dan berfungsi dengan baik.

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }

3

Saya menanganinya dengan terlebih dahulu membuat daftar semua fragmen ( List<Fragment> fragments;) yang akan saya gunakan kemudian menambahkannya ke pager sehingga memudahkan untuk menangani fragmen yang saat ini dilihat.

Begitu:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

jadi ini bisa disebut:

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

jadi saya bisa membuangnya di pernyataan if yang hanya akan berjalan jika itu berada di fragmen yang benar

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

tapi itu hanya pendekatan hack dan slash saya tetapi berhasil untuk saya, saya menggunakannya jangan lakukan perubahan relevan untuk fragmen saya saat ini ditampilkan ketika tombol kembali ditekan.


1
jawaban terbaik untukku
Sonu Kumar

3

Ini berdasarkan jawaban Steven di atas. Ini akan mengembalikan instance fragmen aktual yang sudah dilampirkan ke aktivitas induk.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }

2

Saya tidak dapat menemukan cara yang sederhana dan bersih untuk melakukan ini. Namun, widget ViewPager hanyalah ViewGroup lain, yang menampung fragmen Anda. ViewPager memiliki fragmen ini sebagai anak langsung. Jadi Anda bisa mengulanginya (menggunakan .getChildCount () dan .getChildAt ()), dan lihat apakah instance fragmen yang Anda cari saat ini dimuat ke dalam ViewPager dan dapatkan referensi untuk itu. Misalnya, Anda dapat menggunakan beberapa bidang ID unik statis untuk membedakan fragmen.

Perhatikan bahwa ViewPager mungkin tidak memuat fragmen yang Anda cari karena ini adalah wadah virtual seperti ListView.


1
Terima kasih atas jawaban Anda, saya mengambilnya dengan adpter.getItem (); Saya mahasiswa baru dalam pemrograman Android. sangat menghargai kamu. Sekarang saya dapat mengambil ListFragment dan saya ingin menambahkan footerView, Sementara saya melakukan ini di Aktivitas saya kemudian cetak logcat: "java.lang.IllegalStateException: Tampilan konten belum. Dibuat". Saya tahu mengapa, tetapi saya mengalami kesulitan dalam berurusan dengan itu.
Qun Qin

1
FragmentActivity menggunakan metode onAttachFragment (), dosis ini berfungsi untuk konten fragmen ViewPager?
Vasil Valchev

2

FragmentPagerAdapter adalah pabrik fragmen. Untuk menemukan fragmen berdasarkan posisinya jika masih dalam memori gunakan ini:

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

Kode sampel untuk v4 mendukung api.


Ini mengembalikan nol di onresume (). Adakah yang tahu mengapa dan bagaimana cara memperbaikinya?
seema

2

Anda tidak perlu menelepon getItem()atau metode lain di tahap selanjutnya untuk mendapatkan referensi dari Fragmenthost yang ada di dalamnya ViewPager. Jika Anda ingin memperbarui beberapa data di dalam Fragmentkemudian gunakan pendekatan ini: Perbarui ViewPager secara dinamis?

Kuncinya adalah mengatur data baru di dalam Adaperdan menelepon notifyDataSetChanged()yang pada gilirannya akan memanggil getItemPosition(), memberikan Anda referensi Anda Fragmentdan memberi Anda kesempatan untuk memperbaruinya. Semua cara lain mengharuskan Anda untuk tetap merujuk pada diri sendiri atau peretasan lain yang bukan solusi yang baik.

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(xyzData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}

Saya tidak mengerti di sini, Anda memerlukan referensi Fragmen untuk menggunakan getItemPosition (), jadi sebaiknya Anda tidak menggunakan getItemPosition, eh?

getItemPosition()adalah metode di adaptor Anda. Anda tidak akan menyebutnya secara langsung. Anda memiliki referensi adaptor Anda sehingga Anda memanggil adapter.notifyDataSetChanged()yang pada gilirannya akan memanggil getItemPosition()adaptor Anda dengan melewati referensi Anda Fragment. Anda dapat melihat implementasi penuh dalam aksi di sini stackoverflow.com/questions/19891828/…
M-WaJeEh

Saya sudah membacanya, dan saya masih belum mengerti. Anda masih membutuhkan referensi langsung ke fragmen-fragmen itu untuk melakukan panggilan terhadap mereka, bukan? Anda menyebutkannya sebagai peretasan tetapi saya tidak melihat alternatifnya; adapter.getItem (i) jelas tidak akan berfungsi.

2
Oke, saya sudah memperbarui jawaban saya untuk menjelaskan lebih lanjut. Tentu saja referensi diperlukan untuk memperbarui Fragmenttetapi bagaimana untuk mendapatkan referensi dapat diperdebatkan. Solusi lain mendapatkan referensi dari FragmentManagermenggunakan string yang mirip "android:switcher:"+idatau kembali POSITION_NONEdari getItemosition()menyebabkan semua fragmen dibuat ulang sendiri.
M-WaJeEh

Terima kasih, ini jauh lebih masuk akal dan cocok dengan pengalaman saya (jadi saya mungkin tidak melakukan kesalahan, ha).

2

Harus meluas FragmentPagerAdapterke kelas adaptor ViewPager Anda.
Jika Anda menggunakan FragmentStatePagerAdaptermaka Anda tidak akan dapat menemukan Fragmentdengan AndaID

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

Cara menggunakan metode ini: -

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;

2

Hai saya telah menjawab pertanyaan ini di sini . Pada dasarnya, Anda perlu mengganti

InstantiateItem objek publik (wadah ViewGroup, posisi int)

metode FragmentStatePagerAdapter.


1

Solusi terbaik adalah dengan menggunakan ekstensi yang kami buat di CodePath yang disebut SmartFragmentStatePagerAdapter . Mengikuti panduan itu, ini membuat pengambilan fragmen dan fragmen yang saat ini dipilih dari ViewPager secara signifikan lebih mudah. Itu juga melakukan pekerjaan yang lebih baik mengelola memori fragmen yang tertanam dalam adaptor.


0

Cara termudah dan paling ringkas. Jika semua fragmen Anda ViewPagerberasal dari kelas yang berbeda, Anda dapat mengambil dan membedakannya sebagai berikut:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}

Ini juga salah, karena ada beberapa fragmen yang dilampirkan ketika Anda menggunakan ViewPager. ada fragmen halaman saat ini, dan ada satu di sebelah kiri dan satu di sebelah kanannya. Ini memungkinkan pengguna untuk meluncur di antara mereka tanpa harus menginisialisasi mereka hanya ketika pengguna mencapai mereka.
pengembang android

0

Saya menerapkan ini dengan mudah dengan pendekatan yang sedikit berbeda.

Metode FragmentAdapter.getItem kustom saya mengembalikan bukan MyFragment baru (), tetapi contoh MyFragment yang dibuat dalam konstruktor FragmentAdapter.

Dalam aktivitas saya, saya kemudian mendapatkan fragmen dari adaptor, periksa apakah itu instance dari fragmen yang diperlukan, lalu cor dan gunakan metode yang diperlukan.


0

Buat id sumber daya integer di /values/integers.xml

<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>

Kemudian dalam fungsi getItem PagerAdapter:

public Fragment getItem(int position) {

        Fragment fragment = null;

        if (position == 0) {
            fragment = FragmentOne.newInstance();
            mViewPager.setTag(R.integer.page1,fragment);

        }
        else if (position == 1) {

            fragment = FragmentTwo.newInstance();
            mViewPager.setTag(R.integer.page2,fragment);

        } else if (position == 2) {

            fragment = FragmentThree.newInstance();
            mViewPager.setTag(R.integer.page3,fragment);

        }

        return fragment;
        }

Kemudian dalam aktivitas menulis fungsi ini untuk mendapatkan referensi fragmen:

private Fragment getFragmentByPosition(int position) {
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = (Fragment) mViewPager.getTag(R.integer.page1);
            break;

        case 1:

            fragment = (Fragment) mViewPager.getTag(R.integer.page2);
            break;

        case 2:
            fragment = (Fragment) mViewPager.getTag(R.integer.page3);
            break;
            }

            return fragment;
    }

Dapatkan referensi fragmen dengan memanggil fungsi di atas dan kemudian serahkan ke fragmen khusus Anda:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }

0

Cara mudah untuk beralih pada fragmen di manajer fragmen. Temukan viewpager, yang memiliki argumen posisi bagian, ditempatkan di newInstance PlaceholderFragment statis publik (int sectionNumber) .

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

0

Dalam Fragmen

public int getArgument(){
   return mPage;
{
public void update(){

}

Dalam FragmentActivity

List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
    if((f instanceof PageFragment)&&(!f.isDetached())){
          PageFragment pf = (PageFragment)f;   
          if(pf.getArgument()==pager.getCurrentItem())pf.update();
    }
}

0

di TabLayout ada beberapa tab untuk Fragment. Anda dapat menemukan fragmen dengan Tag menggunakan indeks fragmen.

Misalnya indeks untuk Fragment1 adalah 0, jadi dalam findFragmentByTag()metode, lulus tag untuk Viewpager. Setelah menggunakan fragmentTransaction Anda dapat menambahkan, ganti fragmen.

String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);


-1

Ok untuk adaptor FragmentStatePagerAdaptersaya mendanai solusi:

di FragmentActivity Anda:

ActionBar mActionBar = getSupportActionBar(); 
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));

viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);

dan buat sebuah metode di kelas Anda FragmentActivity - Sehingga metode itu memberi Anda akses ke Fragmen Anda, Anda hanya perlu memberikannya posisi fragmen yang Anda inginkan:

public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}

di Adaptor Anda:

public class MyPagerAdapter extends FragmentStatePagerAdapter {

private final ActionBar actionBar;
private final FragmentManager fragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}

@Override
public int getCount() {
return this.actionBar.getTabCount();
}

@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}

private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}

}

-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

indexadalah tempat fragmen dalam adaptor seperti yang Anda tambahkan fragment1dulu sehingga retreive fragment1pass indexsebagai 0 dan seterusnya untuk istirahat

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.