Mendapatkan instance Fragment saat ini di viewpager


210

Di bawah ini adalah kode saya yang 3 Fragment classesmasing-masing tertanam dengan masing-masing 3 tab ViewPager. Saya punya opsi menu. Seperti ditunjukkan dalam onOptionsItemSelected(), dengan memilih opsi, saya perlu memperbarui fragmen yang saat ini terlihat. Untuk memperbarui itu saya harus memanggil metode yang ada di kelas fragmen. Bisakah seseorang menyarankan cara memanggil metode itu?

public class MainActivity  extends ActionBarActivity {

     ViewPager ViewPager;
     TabsAdapter TabsAdapter;

     @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            ViewPager = new ViewPager(this);
            ViewPager.setId(R.id.pager);
            setContentView(ViewPager);

            final ActionBar bar = getSupportActionBar();

            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

            //Attaching the Tabs to the fragment classes and setting the tab title.
            TabsAdapter = new TabsAdapter(this, ViewPager);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
                    FragmentClass1.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
              FragmentClass2.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
              FragmentClass3.class, null);


            if (savedInstanceState != null) {
                bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
            }

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()) {

            case R.id.addText:

           **// Here I need to call the method which exists in the currently visible Fragment class**

                    return true;

            }

            return super.onOptionsItemSelected(item);
        }


     @Override
     protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
            outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());

     }

     public static class TabsAdapter extends FragmentPagerAdapter
      implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

      private final Context mContext;
            private final ActionBar mActionBar;
            private final ViewPager mViewPager;
            private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

            static final class TabInfo {
                private final Class<?> clss;
                private final Bundle args;

                TabInfo(Class<?> _class, Bundle _args) {
                    clss = _class;
                    args = _args;
                }
            }

      public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
       super(activity.getSupportFragmentManager());
                mContext = activity;
                mActionBar = activity.getSupportActionBar();
                mViewPager = pager;
                mViewPager.setAdapter(this);
                mViewPager.setOnPageChangeListener(this);
            }

      public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
                TabInfo info = new TabInfo(clss, args);
                tab.setTag(info);
                tab.setTabListener(this);
                mTabs.add(info);
                mActionBar.addTab(tab);
                notifyDataSetChanged();

            }

      @Override
      public void onPageScrollStateChanged(int state) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageSelected(int position) {
       // TODO Auto-generated method stub
       mActionBar.setSelectedNavigationItem(position);
      }

      @Override
      public void onTabReselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onTabSelected(Tab tab, FragmentTransaction ft) {
       Object tag = tab.getTag();
                for (int i=0; i<mTabs.size(); i++) {
                    if (mTabs.get(i) == tag) {
                        mViewPager.setCurrentItem(i);

                    }
                }

                tabPosition = tab.getPosition();
      }

      @Override
      public void onTabUnselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public Fragment getItem(int position) {
       TabInfo info = mTabs.get(position);
                return Fragment.instantiate(mContext, info.clss.getName(), info.args);
      }

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

     }

    }

Misalkan di bawah ini adalah kelas fragmen dengan metode yang updateList()ingin saya panggil:

 public class FragmentClass1{

    ArrayList<String> originalData;


    @Override
         public View onCreateView(LayoutInflater inflater, ViewGroup container,
           Bundle savedInstanceState) {

          View fragmentView = inflater.inflate(R.layout.frag1, container, false);

          originalData = getOriginalDataFromDB();

          return fragmentView;

         }


    public void updateList(String text)
    {
       originalData.add(text);
       //Here I could do other UI part that need to added
    }
}

metode fragmen mana yang ingin Anda panggil?
Biraj Zalavadia

@BirajZalavadia Metode yang saya tentukan sendiri, yang memiliki parameter di dalamnya dan menggunakan variabel instan dari kelas fragmen yang telah diinisialisasi saat membuat tampilan genap.
rick

1
dapatkah Anda memberikan nama Kelas dari fragmen Anda yang ada di viewpager?
Biraj Zalavadia


Cara paling sederhana untuk mengakses fragmen yang terlihat adalah melalui stackoverflow.com/questions/7379165/… , lihat dua jawaban teratas.
Luksprog

Jawaban:


205

dengan memilih opsi, saya perlu memperbarui fragmen yang saat ini terlihat.

Cara sederhana untuk melakukan ini adalah menggunakan trik yang terkait dengan FragmentPagerAdapterimplementasi:

case R.id.addText:
     Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
     // based on the current position you can then cast the page to the correct 
     // class and call the method:
     if (ViewPager.getCurrentItem() == 0 && page != null) {
          ((FragmentClass1)page).updateList("new item");     
     } 
return true;

Pikirkan kembali konvensi penamaan variabel Anda, gunakan sebagai nama variabel, nama kelas sangat membingungkan (jadi tidak ViewPager ViewPager, gunakan ViewPager mPagermisalnya).


23
Apakah itu tag fragmen yang tahan di masa mendatang, jika API berubah?
Maarten

7
@ Maarten Tidak, ini hanya peretasan umum yang telah digunakan sejak adaptor muncul (dan kode sumbernya tersedia), belum berubah. Jika Anda menginginkan sesuatu yang lebih andal, Anda perlu menggunakan opsi lain, yang paling menonjol adalah mengganti instantiateItem()metode dan mendapatkan referensi ke fragmen yang tepat.
Luksprog

5
Setelah berjam-jam frustrasi dan meminta halaman langsung dari mAdapter.getItem(position), luar biasa ... Setidaknya sekarang saya tahu bahwa 8512 percobaan lain tidak berhasil. Terima kasih
Diolor

29
Catatan ini tidak berfungsi jika Anda menggunakan FragmentStatePagerAdapter daripada FragmentPagerAdapter.
Shawn Lauzon

3
@ShawnLauzon The FragmentStatePagerAdapter memiliki implementasi yang berbeda, dalam hal ini Anda memanggil metode instantiateItem () untuk mendapatkan fragmen yang terlihat.
Luksprog

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

29
Google harus menyediakan FragmentPageAdapter.getCurrentPrimaryItem () mengembalikan mCurrentPrimaryItem.
eugene

1
Saya menggunakan teknik ini juga. Saya juga mendefinisikan PagerFragment dengan metode onPageSelected/ onPageDeselecteddan memiliki semua fragmen halaman saya memperpanjangnya. Kemudian setPrimaryitemdapat memanggil metode ini dengan tepat ketika pengguna menggesek ke halaman baru. Ini berarti Anda dapat menerapkan strategi malas untuk memuat data di halaman yang bahkan tidak ditampilkan. Namun Anda harus ingat bahwa selama transisi halaman terlihat lebih baik jika halaman berikutnya sudah diisi dengan data, jadi malas memuat semua data onPageSelectedmungkin tidak ideal.
JHH

3
Mengapa ifpernyataan itu? Fragmen hanya memanggil equalsmetode objek, yang merupakan perbandingan dangkal. Jadi mengapa tidak selalu menelepon mCurrentFragment = ((Fragment) object);?
Overclover

mencoba dan berfungsi dengan baik, cukup masukkan getCurrentFragment () ke Fragmen spesifik yang seharusnya
PhilipJ

113

Pertama-tama, perhatikan semua halaman fragmen "aktif". Dalam hal ini, Anda melacak halaman fragmen di FragmentStatePagerAdapter, yang digunakan oleh ViewPager.

@Override
public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

Untuk menghindari menyimpan referensi ke halaman fragmen "tidak aktif", Anda perlu menerapkan metode destroyItem (...) dari FragmentStatePagerAdapter:

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

dan ketika Anda perlu mengakses halaman yang terlihat saat ini, Anda kemudian memanggil:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

Di mana metode getFragment (int) MyAdapter terlihat seperti ini:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

Semoga bisa membantu!


Bisakah Anda jelaskan dengan jelas? Di mana saya harus menyimpan kelas FragmentStatePagerAdapter ini dalam kode saya? BTW Saya memiliki 3 kelas fragmen, bukan MyFragmentClass tunggal.
rick

7
Bahkan lebih baik jika Anda memperbarui mPageReferenceMap di instantiateItem daripada getItem karena itu juga berfungsi setelah perubahan orientasi. '@Override Objek publik instantiateItem (wadah ViewGroup, posisi int) {Fragmen fragmen = (Fragmen) Super.instantiateItem (wadah, posisi); mPageReferenceMap.put (posisi, fragmen); mengembalikan fragmen; } '
pmellaaho

Apa tipe mPageReferenceMap?
DoruAdryan

10
Jawaban ini sangat buruk! Anda seharusnya tidak menyimpan cache dari ViewPager secara manual karena itu menanganinya sendiri. ViewPager memutuskan kapan fragmen harus dialokasikan atau tidak, apa yang harus dijeda dan kapan, menyimpan referensi pada setiap fragmen akan menambahkan beberapa overhead yang tidak berguna dan tidak dioptimalkan untuk memori.
Livio

3
Saya mencoba pendekatan ini tetapi sayangnya itu tidak berhasil ketika aktivitas dibuat ulang. Di Android N dan yang lebih baru, Anda dapat melihat ini saat menggunakan fitur multi jendela. Saat aplikasi Anda terbuka, tahan lama tombol 'terbaru' (yang kotak). Aktivitas dan fragmen diciptakan kembali dari diselamatkanInstanceState, adaptor dibuat ulang (sehingga mPageReferenceMap sekarang kosong), tetapi getItem tidak dipanggil lagi. Peta tetap kosong sehingga adapter.getFragment (indeks) akan macet.
Martin Konicek

102

Ini adalah satu-satunya cara saya tidak mendapatkan NullPointerException untuk variabel instan dari kelas fragmen tertentu. Ini mungkin bermanfaat bagi orang lain yang terjebak pada hal yang sama. Dalam onOptionsItemSelected (), saya memberi kode cara di bawah ini:

if(viewPager.getCurrentItem() == 0) {
    FragmentClass1 frag1 = (FragmentClass1)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag1.updateList(text); 
} else if(viewPager.getCurrentItem() == 1) {
    FragmentClass2 frag2 = (FragRecentApps)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag2.updateList(text);
}

3
Saya pikir ini adalah jawaban yang paling benar - sejajar dengan desain FragmentStatePagerAdaptertanpa mengesampingkan kode apa pun. Bahkan, itu harus sesederhana fungsi hanya kembali viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
John Pang

39

FragmentStatePagerAdapter memiliki metode publik dengan nama instantiateItem yang mengembalikan fragmen Anda berdasarkan nilai parameter yang ditentukan, metode ini memiliki dua parameter, ViewGroup (ViewPager), dan posisi.

public Object instantiateItem(ViewGroup container, int position);

Menggunakan metode ini untuk mendapatkan fragmen posisi yang ditentukan,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);

5
Tetapi ini tidak mengembalikan fragmen yang sudah dipakai saat ini, tetapi yang baru, bukan? Jadi
beri

1
@Ixx Tidak itu tidak membuat fragmen baru. Saya pikir nama metode salah di sini.
Bugs Terjadi

15

Saya tahu ini sudah terlambat tetapi saya memiliki cara yang sangat sederhana untuk melakukannya,

// untuk fragmen dengan kepemilikan 0

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();

10

Ada banyak jawaban di sini yang tidak benar-benar membahas fakta dasar bahwa benar-benar TIDAK ADA CARA untuk melakukan hal ini dengan cara yang dapat diduga, dan dengan cara yang tidak menghasilkan Anda menembak diri sendiri di beberapa titik di masa depan.

FragmentStatePagerAdapteradalah satu-satunya kelas yang tahu cara mengakses fragmen yang dapat dipercaya dengan dilacak oleh FragmentManager- setiap upaya untuk mencoba dan menebak id atau tag fragmen tidak dapat diandalkan, jangka panjang. Dan upaya untuk melacak instances secara manual kemungkinan tidak akan berfungsi dengan baik ketika state disimpan / dipulihkan, karena FragmentStatePagerAdaptermungkin tidak akan memanggil callback ketika mengembalikan state.

Satu-satunya hal yang saya dapat lakukan adalah menyalin kode FragmentStatePagerAdapterdan menambahkan metode yang mengembalikan fragmen, diberi posisi ( mFragments.get(pos)). Perhatikan bahwa metode ini mengasumsikan bahwa fragmen sebenarnya tersedia (yaitu terlihat pada beberapa titik).

Jika Anda sangat berjiwa petualang, Anda dapat menggunakan refleksi untuk mengakses elemen mFragmentsdaftar pribadi , tetapi kemudian kami kembali ke titik awal (nama daftar tidak dijamin tetap sama).


1
untuk menangani "tidak berfungsi dengan baik ketika negara disimpan / dikembalikan", saya mengganti metode saveState (). Agar pager tidak menyimpan fragmen apa pun ketika aktivitas dijeda. berhasil.
AntoineP

2
Itu hanya menambah tambal sulam, tanpa memperbaiki masalah mendasar. Saya tidak berpendapat bahwa itu tidak berhasil - hanya saja itu bukan implementasi yang baik.
Melllvar

8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Keluarkan instance yang diambil dari baris di atas ke fragmen yang ingin Anda kerjakan. Bekerja dengan sangat baik.

viewPager

adalah contoh pager yang mengelola fragmen.


Ini hanya berfungsi jika semua halaman dimuat sebagai Fragmen. Ketika ada misalnya tablayout dengan banyak tab / halaman maka tidak semuanya dimuat, jadi ini bisa meningkatkan indexoutofbounce exception.
progNewbie

@progNewbie ya itu akan membutuhkan kode solusi tambahan.
Gaurav Pangam

@progNewbie Evgeny jawaban di bawah ini akan menangani situasi itu saya pikir
Gaurav Pangam

7

dengan memilih opsi, saya perlu memperbarui fragmen yang saat ini terlihat.

Untuk mendapatkan referensi ke fragmen yang terlihat saat ini, anggap Anda memiliki referensi ViewPagersebagai mPager. Maka langkah-langkah berikut akan mendapatkan referensi ke currentFragment:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

Satu-satunya pemain yang digunakan baris 3 biasanya valid. FragmentStatePagerAdapteradalah adaptor yang berguna untuk ViewPager.


7

Cara terbaik untuk melakukan ini, cukup panggil CallingFragmentName fragment = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager, viewPager.getCurrentItem ()); Ini akan instantiate fragmen panggilan Anda, sehingga tidak akan membuang null pointer exception dan memanggil metode apa pun dari fragmen itu.


6

Fragmen saat ini:

Ini berfungsi jika Anda membuat proyek dengan templat tabbar fragmen.

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

Perhatikan bahwa ini berfungsi dengan implementasi templat aktivitas tab yang standar.


30
Ini tergantung pada implementasi getItem () Anda - ini mungkin mengembalikan instance fragmen baru, yang mungkin bukan yang Anda inginkan.
Tom

Ini adalah bagaimana kamu melakukannya. jika Anda masih memiliki konfigurasi default ketika Anda membuat tabor dengan proyek fragmen. tidak ada yang punya solusi ini. jadi saya pikir itu akan membantu.
hasan

3

Saya telah menggunakan yang berikut ini:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);

1
Ini bergantung pada implementasi pager khusus dari jawaban yang ditemukan di sini: stackoverflow.com/questions/8785221/…
Tom Redman

1
Ini persis apa yang saya coba lakukan tetapi tanpa mengetahui metode yang harus ditimpa, akan membuang waktu - terima kasih!
Bron Davies

2

FragmentStatePagerAdaptermemiliki variabel instance pribadi yang disebut mCurrentPrimaryItemtipe Fragment. Orang hanya bisa bertanya-tanya mengapa Android devs tidak menyediakannya dengan pengambil. Variabel ini dipakai dalam setPrimaryItem()metode. Jadi, timpa metode ini sedemikian rupa agar Anda mendapatkan referensi ke variabel ini. Saya hanya berakhir dengan menyatakan milik saya mCurrentPrimaryItemdan menyalin konten setPrimaryItem()untuk menimpa saya.

Dalam implementasi Anda FragmentStatePagerAdapter :

private Fragment mCurrentPrimaryItem = null;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;
    if (fragment != mCurrentPrimaryItem) {
        if (mCurrentPrimaryItem != null) {
            mCurrentPrimaryItem.setMenuVisibility(false);
            mCurrentPrimaryItem.setUserVisibleHint(false);
        }
        if (fragment != null) {
            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
        }
        mCurrentPrimaryItem = fragment;
    }
}

public TasksListFragment getCurrentFragment() {
    return (YourFragment) mCurrentPrimaryItem;
}

2

Anda dapat menentukan PagerAdapterseperti ini maka Anda akan bisa mendapatkan Fragmentdi ViewPager.

private class PagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

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

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }
}

Untuk mendapatkan arus Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());

2

Ketika kita menggunakan viewPager, cara yang baik untuk mengakses instance fragmen dalam aktivitas adalah instantiateItem (viewpager, index). // indeks- indeks fragmen yang Anda inginkan misalnya.

misalnya saya mengakses contoh fragmen dari 1 index-

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}

2

Dalam implementasi saya sebelumnya, saya menyimpan daftar Fragmen anak untuk dapat mengaksesnya nanti, tetapi ini ternyata implementasi yang salah yang menyebabkan kebocoran memori yang sangat besar.

Saya akhirnya menggunakan instantiateItem(...)metode untuk mendapatkan Fragmen saat ini:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

Atau untuk mendapatkan Fragmen lain di posisi:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

Dari dokumentasi :

Buat halaman untuk posisi yang diberikan. Adaptor bertanggung jawab untuk menambahkan tampilan ke wadah yang diberikan di sini, meskipun itu hanya harus memastikan hal ini dilakukan pada saat ia kembali dari finishUpdate (ViewGroup).


Singkat dan bersih, terima kasih
JimmyFlash

1

Saya memiliki masalah yang sama dan menyelesaikannya menggunakan kode ini.

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

Cukup ganti nama MyFragment dengan nama fragmen Anda dan tambahkan id wadah fragmen Anda.


1

Ini lebih banyak bukti di masa depan daripada jawaban yang diterima:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    /* ------------------------------------------------------------------------------------------ */
    // region Private attributes :

    private Context _context;
    private FragmentManager _fragmentManager;
    private Map<Integer, String> _fragmentsTags = new HashMap<>();

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region Constructor :

    public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {

        super(fragmentManager);

        _context = context;
        _fragmentManager = fragmentManager;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region FragmentPagerAdapter methods :

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

    @Override
    public Fragment getItem(int position) {

        if(_fragmentsTags.containsKey(position)) {

            return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
        }
        else {

            switch (position) {

                case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
                case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
            }
        }

        return null;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        // Instantiate the fragment and get its tag :
        Fragment result = (Fragment) super.instantiateItem(container, position);
        _fragmentsTags.put(position, result.getTag());

        return result;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */
}

Anda harus menggunakan WeakHashMap sebagai gantinya.
Prakash Nadar

1

Skenario yang dipermasalahkan lebih baik dilayani oleh masing-masing Fragmen menambahkan item menu sendiri dan secara langsung menangani onOptionsItemSelected (), seperti yang dijelaskan dalam dokumentasi resmi . Lebih baik menghindari trik yang tidak berdokumen.


Jawaban ini dapat menggunakan lebih banyak detail untuk bagaimana sebenarnya melakukannya. Bagaimana cara menambahkan item menu menyelesaikan ViewPagermasalah?
Suragch

Masalah @Suragch ViewPager ada jika peristiwa menu ditangani di dalam Aktivitas yang meng-host fragmen dan tidak ada jika acara ditangani di dalam fragmen itu sendiri. Tautan menunjukkan bagaimana sebuah fragmen dapat menambahkan item menu sendiri.
Y2i

1

Setelah membaca semua komentar dan jawaban saya akan menjelaskan solusi optimal untuk masalah ini. Pilihan terbaik adalah solusi @ rik, jadi peningkatan saya didasarkan pada miliknya.

Daripada harus meminta setiap FragmentClass suka

if(FragmentClass1){
   ...
if(FragmentClass2){
   ...
}

Buat antarmuka Anda sendiri, dan buat fragmen anak Anda menerapkannya, seperti

public interface MyChildFragment {
    void updateView(int position);
}

Kemudian, Anda dapat melakukan sesuatu seperti ini untuk memulai dan memperbarui fragmen batin Anda.

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

PS Hati-hati di mana Anda meletakkan kode itu, jika Anda memanggil insatiateItem sebelum sistem benar-benar membuatnya, savedInstanceStatefragmen anak Anda akan menjadi nol karenanya

public void onCreate(@Nullable Bundle savedInstanceState){
      super(savedInstanceState)
}

Akan merusak aplikasi Anda.

Semoga berhasil


1

Berdasarkan apa yang dia jawab @chahat jain:

"Ketika kita menggunakan viewPager, cara yang baik untuk mengakses instance fragmen dalam aktivitas adalah instantiateItem (viewpager, index). // indeks-indeks fragmen yang Anda inginkan instance."

Jika Anda ingin melakukannya di kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 ke instance fragmen 0

// ================================================ ========================= // // ##################### ######## Contoh penggunaan ############################### // // == ================================================== ===================== //

Berikut adalah contoh lengkap untuk mendapatkan visi yang kalah tentang

di sini adalah veiewPager saya dalam file .xml

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

Dan aktivitas rumah di mana saya memasukkan tab

...
import kotlinx.android.synthetic.main.movie_tab.*

class HomeActivity : AppCompatActivity() {

    lateinit var  adapter:HomeTabPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    }



    override fun onCreateOptionsMenu(menu: Menu) :Boolean{
            ...

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
          ...

            override fun onQueryTextChange(newText: String): Boolean {

                if (mv_viewpager.currentItem  ==0)
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                    if ( fragment is ListMoviesFragment)
                        fragment.onQueryTextChange(newText)
                }
                else
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
                    if ( fragment is ListShowFragment)
                        fragment.onQueryTextChange(newText)
                }
                return true
            }
        })
        return super.onCreateOptionsMenu(menu)
    }
        ...

}

0

Dalam Aktivitas saya, saya memiliki:

int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int pos) {
        currentPage = pos;//update current page
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageScrollStateChanged(int arg0) {}
});



@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);
    if(fragment instanceof Fragment1)
        fragments.put(0, fragment);
    if(fragment instanceof Fragment2)
        fragments.put(2, fragment);
    if(fragment instanceof Fragment3)
        fragments.put(3, fragment);
    if(fragment instanceof Fragment4)
        fragments.put(4, fragment);
}

Then I have the following method for getting the current fragment

public Fragment getCurrentFragment() {
    return fragments.get(currentPage);
}

0
final ViewPager.OnPageChangeListener onPageChangeListener =
    new ViewPager.OnPageChangeListener() {
      @Override public void onPageSelected(int position) {
        switch (position) {
          case 0:
            FragmentClass1 frag1 =
                (FragmentClass1) viewPager.getAdapter()
                    .instantiateItem(viewPager, viewPager.getCurrentItem());
            frag1.updateList("Custom text");
            break;
          case 1:
            break;
          case 2:
            break;
        }
      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

      }

      @Override public void onPageScrollStateChanged(int state) {
      }
    };


 viewPager.addOnPageChangeListener(onPageChangeListener);

viewPager.setAdapter(adapter);


viewPager.post(new Runnable() {
  @Override public void run() {
    onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
  }
});

Kadang-kadang fragmen dapat mengirim objek nol, sehingga Anda bisa menjalankan Runnable baru untuk menyelesaikan masalah saat memuat pertama.

Terima kasih, Rick


Harap tambahkan beberapa teks yang menjelaskan mengapa kode ini akan menyelesaikan masalah OP. Juga, mengingat berapa banyak jawaban lain yang ada, jelaskan mengapa jawaban ini lebih baik daripada yang sudah diberikan. Bantu orang lain untuk mengerti.
APC

0

Mengganti setPrimaryItem dari FragmentPagerAdapter Anda: objek adalah fragmen yang terlihat:

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

0

Cukup dapatkan item saat ini dari pager dan kemudian tanyakan adaptor Anda ke fragmen posisi itu.

 int currentItem = viewPager.getCurrentItem();
    Fragment item = mPagerAdapter.getItem(currentItem);
    if (null != item && item.isVisible()) {
       //do whatever want to do with fragment after doing type checking
        return;
    }

3
Bagaimana jika getItemmenciptakan contoh baru
Prakash Nadar

0

Untuk mendapatkan fragmen saat ini - dapatkan posisi di ViewPager di public void onPageSelected (posisi int final) , lalu

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

SECTNUM - argumen posisi yang ditetapkan dalam PlaceStaceFragment public static baruInstance (int sectionNumber); dari Fragmen

getChildFragmentManager () atau getFragmentManager () - tergantung pada cara membuat SectionsPagerAdapter


0

Anda dapat menerapkan BroadcastReceiver di Fragmen dan mengirim Intent dari mana saja. Penerima fragmen dapat mendengarkan tindakan spesifik dan memanggil metode instance.

Satu peringatan adalah memastikan komponen View sudah dipakai dan (dan untuk beberapa operasi, seperti menggulir daftar, ListView harus sudah dirender).


0

Ini adalah retas paling sederhana:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(kode kotlin)

Panggil saja instantiateItem(viewPager, viewPager.getCurrentItem()dan masukkan ke Fragment. Item Anda sudah akan dipakai. Untuk memastikan Anda bisa menambahkan cek getCount.

Bekerja dengan keduanya FragmentPagerAdapterdan FragmentStatePagerAdapter!


0

Jika pager Anda ada di dalam Fragmen maka gunakan ini:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

Di mana R.id.myViewPagerIdid ViewPager Anda di dalam Layout xml.


Ini hanya berfungsi dengan FragmentPageAdapter normal dan tidak dengan FragmentStatePageAdapter.
progNewbie

0

Anda dapat mendeklarasikan Array fragmen sebagai fragmen register

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Maka Anda dapat menggunakannya sebagai

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}

Jika Anda memutuskan untuk pergi dengan cara itu, Anda juga harus menerapkan destroyItem () dan menghapus instance yang dihancurkan dari Frag yang terdaftar, jika tidak, Anda akan mengalami kebocoran memori.
dephinera

Itu saran yang bagus. Anda dipersilakan untuk mengedit dalam jawaban.
Hamza Khan

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.