ViewPager PagerAdapter tidak memperbarui View

597

Saya menggunakan ViewPager dari perpustakaan kompatibilitas. Saya telah berhasil menampilkan beberapa tampilan yang bisa saya lihat.

Namun, saya mengalami kesulitan mencari tahu cara memperbarui ViewPager dengan serangkaian Tampilan baru.

Saya sudah mencoba segala macam hal seperti menelepon mAdapter.notifyDataSetChanged(), mViewPager.invalidate()bahkan membuat adaptor baru setiap kali saya ingin menggunakan Daftar data baru.

Tidak ada yang membantu, tampilan teks tetap tidak berubah dari data asli.

Pembaruan: Saya membuat proyek uji kecil dan saya hampir dapat memperbarui pandangan. Saya akan menempelkan kelas di bawah ini.

Apa yang tampaknya tidak memperbarui adalah tampilan ke-2, 'B' tetap, itu akan menampilkan 'Y' setelah menekan tombol pembaruan.

public class ViewPagerBugActivity extends Activity {

    private ViewPager myViewPager;
    private List<String> data;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        data = new ArrayList<String>();
        data.add("A");
        data.add("B");
        data.add("C");

        myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
        myViewPager.setAdapter(new MyViewPagerAdapter(this, data));

        Button updateButton = (Button) findViewById(R.id.update_button);
        updateButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                updateViewPager();
            }
        });
    }

    private void updateViewPager() {
        data.clear();
        data.add("X");
        data.add("Y");
        data.add("Z");
        myViewPager.getAdapter().notifyDataSetChanged();
    }

    private class MyViewPagerAdapter extends PagerAdapter {

        private List<String> data;
        private Context ctx;

        public MyViewPagerAdapter(Context ctx, List<String> data) {
            this.ctx = ctx;
            this.data = data;
        }

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

        @Override
        public Object instantiateItem(View collection, int position) {
            TextView view = new TextView(ctx);
            view.setText(data.get(position));
            ((ViewPager)collection).addView(view);
            return view;
        }

        @Override
        public void destroyItem(View collection, int position, Object view) {
             ((ViewPager) collection).removeView((View) view);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Parcelable saveState() {
            return null;
        }

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1) {
        }

        @Override
        public void startUpdate(View arg0) {
        }

        @Override
        public void finishUpdate(View arg0) {
        }
    }
}
C0deAttack
sumber
1
Silakan lihat stackoverflow.com/questions/12510404/… untuk bug potensial dengan FragmentStatePagerAdapter.
samis
2
Maaf mengeruk ini. Pertanyaan Anda sangat membantu saya, terima kasih! Satu hal yang saya tidak dapatkan adalah bagaimana referensi ke data di PagerAdapter berubah ketika Anda memperbaruinya di Activity
Ewanw
Buat adaptor Anda memperluas BaseAdapter Lihat ini: stackoverflow.com/questions/13664155/…
1
Rupanya jika Anda mengatur adaptor lagi ke pager tampilan Anda, maka itu ulang.
EpicPandaForce
saya punya masalah di pager stackoverflow.com/questions/41217237/…
chris

Jawaban:

856

Ada beberapa cara untuk mencapai ini.

Opsi pertama lebih mudah, tetapi sedikit lebih tidak efisien.

Ganti getItemPositiondengan Anda PagerAdapterseperti ini:

public int getItemPosition(Object object) {
    return POSITION_NONE;
}

Dengan cara ini, saat Anda menelepon notifyDataSetChanged(), pager tampilan akan menghapus semua tampilan dan memuat semuanya. Dengan demikian efek reload diperoleh.

Opsi kedua, yang disarankan oleh Alvaro Luis Bustamante (sebelumnya alvarolb) , adalah setTag()metode instantiateItem()ketika membuat tampilan baru. Kemudian, alih-alih menggunakan notifyDataSetChanged(), Anda dapat menggunakan findViewWithTag()untuk menemukan tampilan yang ingin Anda perbarui.

Pendekatan kedua sangat fleksibel dan berkinerja tinggi. Kudos to alvarolb untuk penelitian asli.

rui.araujo
sumber
4
Lebih baik daripada pekerjaan saya di sekitar, tampaknya tidak memiliki efek samping, terima kasih.
C0deAttack
3
Saya punya masalah serupa. ViewPager saya akan menampilkan hasil searc baru tetapi tidak secara default kembali ke entri pertama di kursor. Adakah yang tahu cara mengatur ulang posisi saat memperbarui dataset?
mAndroid
1
@mAndroid Anda harus mengajukan pertanyaan terpisah dengan rincian lebih lanjut.
rui.araujo
1
mengembalikan POSITION_NONE tampaknya menambah banyak inefisiensi pada keseluruhan aplikasi karena ini menyebabkan Android menghapus tampilan yang terkait dengan posisi yang ditanyakan. Tampilan kemudian perlu dibuat kembali lagi sebelum ditampilkan. Memecahkan masalah tampilan yang tidak diperbarui, tetapi mungkin bukan solusi terbaik untuk tata letak yang kompleks.
wufoo
11
Jawaban yang lebih baik (tanpa menghapus semua item) -> stackoverflow.com/a/10852046/898056
yhpark
484

Saya tidak berpikir ada bug apa pun di Internet PagerAdapter. Masalahnya adalah bahwa memahami cara kerjanya sedikit rumit. Melihat solusi yang dijelaskan di sini, ada kesalahpahaman dan oleh karena itu penggunaan pandangan instantiated yang buruk dari sudut pandang saya.

Beberapa hari terakhir saya bekerja dengan PagerAdapterdan ViewPager, dan saya menemukan yang berikut:

The notifyDataSetChanged()metode pada PagerAdapterhanya akan memberitahukan ViewPagerbahwa halaman yang mendasari telah berubah. Sebagai contoh, jika Anda telah membuat / menghapus halaman secara dinamis (menambah atau menghapus item dari daftar Anda), itu ViewPagerharus diurus. Dalam hal ini saya berpikir bahwa ViewPagermenentukan apakah tampilan baru harus dihapus atau dipakai menggunakan metode getItemPosition()dan getCount().

Saya pikir ViewPager, setelah notifyDataSetChanged()panggilan telepon itu dilihat anak dan diperiksa posisi mereka dengan getItemPosition(). Jika untuk tampilan anak-anak metode ini kembali POSITION_NONE, ViewPagermemahami bahwa tampilan telah dihapus, memanggil destroyItem(), dan menghapus tampilan ini.

Dengan cara ini, mengesampingkan getItemPosition()untuk selalu kembali POSITION_NONEbenar-benar salah jika Anda hanya ingin memperbarui konten halaman, karena tampilan yang dibuat sebelumnya akan dihancurkan dan yang baru akan dibuat setiap kali Anda menelepon notifyDatasetChanged(). Tampaknya tidak begitu salah hanya untuk beberapa TextViews, tetapi ketika Anda memiliki pandangan yang kompleks, seperti ListViews yang dihuni dari database, ini bisa menjadi masalah nyata dan pemborosan sumber daya.

Jadi ada beberapa pendekatan untuk mengubah konten tampilan secara efisien tanpa harus menghapus dan membuat instance tampilan lagi. Itu tergantung pada masalah yang ingin Anda pecahkan. Pendekatan saya adalah menggunakan setTag()metode untuk tampilan instantiated dalam instantiateItem()metode ini. Jadi ketika Anda ingin mengubah data atau membatalkan tampilan yang Anda butuhkan, Anda dapat memanggil findViewWithTag()metode di ViewPageruntuk mengambil tampilan yang sebelumnya dipakai dan memodifikasi / menggunakannya seperti yang Anda inginkan tanpa harus menghapus / membuat tampilan baru setiap kali Anda inginkan untuk memperbarui beberapa nilai.

Bayangkan misalnya Anda memiliki 100 halaman dengan 100 TextViews dan Anda hanya ingin memperbarui satu nilai secara berkala. Dengan pendekatan yang dijelaskan sebelumnya, ini berarti Anda menghapus dan membuat Instansi 100 TextViewpada setiap pembaruan. Ini tidak masuk akal...

Alvaro Luis Bustamante
sumber
11
+1 - Solusi Anda tidak hanya berfungsi seperti jimat, saya mengalami masalah persis seperti yang Anda jelaskan di sini ketika saya harus memperbarui halaman yang berisi tab dengan tampilan daftar, tampilan teks, dan gambar. (OutOfErrorExceptions dan semacamnya ...) Terima kasih!
schlingel
3
@alvarolb: Halo, saya tidak benar-benar tahu maksud Anda tentang setTagmetode onInstantiateItem, Apakah Anda ingin memperbarui jawaban ini dengan beberapa pengkodean? Terima kasih.
Menara Huy
35
Akan sempurna jika Anda menulis contoh.
Sami Eltamawy
13
Seperti seseorang berkata: sebuah contoh akan dihargai!
Jey10
15
6 tahun sekarang, tidak ada yang bisa memberikan contoh.
Oussaki
80

Ubah FragmentPagerAdapterke FragmentStatePagerAdapter.

Ganti getItemPosition()metode dan kembali POSITION_NONE.

Akhirnya, ia akan mendengarkan notifyDataSetChanged()pager tampilan.

Kit
sumber
Saya pikir Anda harus menerapkan seluruh getItemPosition dengan benar DAN mengembalikan POSITION_NONE jika fragmen tidak ditemukan.
tkhduracell
46

Jawaban yang diberikan oleh alvarolb jelas merupakan cara terbaik untuk melakukannya. Membangun atas jawabannya, cara mudah untuk menerapkan ini adalah dengan hanya menyimpan pandangan aktif berdasarkan posisi:

SparseArray<View> views = new SparseArray<View>();

@Override
public Object instantiateItem(View container, int position) {
    View root = <build your view here>;
    ((ViewPager) container).addView(root);
    views.put(position, root);
    return root;
}

@Override
public void destroyItem(View collection, int position, Object o) {
    View view = (View)o;
    ((ViewPager) collection).removeView(view);
    views.remove(position);
    view = null;
}

Kemudian sekali dengan mengganti notifyDataSetChangedmetode Anda dapat menyegarkan tampilan ...

@Override
public void notifyDataSetChanged() {
    int key = 0;
    for(int i = 0; i < views.size(); i++) {
       key = views.keyAt(i);
       View view = views.get(key);
       <refresh view with new data>
    }
    super.notifyDataSetChanged();
}

Anda benar-benar dapat menggunakan kode serupa di instantiateItemdan notifyDataSetChangeduntuk menyegarkan tampilan Anda. Dalam kode saya, saya menggunakan metode yang sama persis.

Grimmace
sumber
8
dapatkah Anda memberikan contoh adaptor lengkap? apakah ini dilakukan menggunakan Fragmen atau tidak?
9
<menyegarkan tampilan dengan data baru> ?? apa artinya itu baik kita harus menambahkan dia melihat di sini atau tidak sama sekali?
Akarsh M
Metode ini memperbarui semua tampilan. Jika Anda hanya ingin memperbarui satu tampilan, maka Anda dapat menulis metode notifyDataItemChanged Anda sendiri seperti ini: public void notifyDataItemChanged (int pos) {TextView tv = (TextView) views.get (pos) .findViewById (R.id.tv); tv.setText (list.get (pos)); super.notifyDataSetChanged (); }
Kai Wang
Kode ini macet jika ukuran halaman baru kurang dari ukuran lama
Anton Duzenko
@AntonDuzenko benar, menghapus pandangan cukup sulit.
MLProgrammer-CiM
28

Punya masalah yang sama. Bagi saya ini berhasil memperluas FragmentStatePagerAdapter, dan mengganti metode di bawah ini:

@Override
public Parcelable saveState() {
    return null;
}

@Override
public void restoreState(Parcelable state, ClassLoader loader) {

}
Mario Mosca
sumber
Ini adalah satu-satunya solusi yang bekerja untuk saya juga. Kasing saya tidak memperbarui fragmen, tetapi menghapus atau menambahkan fragmen secara dinamis. Tanpa memperluas FragmentStatePagerAdapter, ViewPager mengembalikan fragmen yang di-cache, yang merupakan posisi yang salah. Terima kasih!
Sira Lam
Bekerja dengan baik di perpustakaan dukungan 28.0.0
Oleksii K.
Override untuk melakukan apa? Bagaimana cara membuat objek keadaan yang terkait dengan Adaptor?
Phani Rithvij
Terimakasih kawan. Solusi ini hanya berfungsi
Parthi
20

Setelah berjam-jam frustrasi ketika mencoba semua solusi di atas untuk mengatasi masalah ini dan juga mencoba banyak solusi pada pertanyaan serupa lainnya seperti ini , ini dan ini yang semuanya GAGAL dengan saya untuk menyelesaikan masalah ini dan membuat ViewPageruntuk menghancurkan yang lama Fragmentdan mengisi pagerdengan yang baru Fragment. Saya telah memecahkan masalah sebagai berikut:

1) Buat ViewPagerkelas untuk diperluas FragmentPagerAdaptersebagai berikut:

 public class myPagerAdapter extends FragmentPagerAdapter {

2) Buat Item untuk ViewPagertoko itu titledan fragmentsebagai berikut:

public class PagerItem {
private String mTitle;
private Fragment mFragment;


public PagerItem(String mTitle, Fragment mFragment) {
    this.mTitle = mTitle;
    this.mFragment = mFragment;
}
public String getTitle() {
    return mTitle;
}
public Fragment getFragment() {
    return mFragment;
}
public void setTitle(String mTitle) {
    this.mTitle = mTitle;
}

public void setFragment(Fragment mFragment) {
    this.mFragment = mFragment;
}

}

3) Buat konstruktor ViewPagertake FragmentManagerinstance saya untuk menyimpannya di saya classsebagai berikut:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mPagerItems = pagerItems;
}

4) Buat metode untuk mengatur ulang adapterdata dengan data baru dengan menghapus semua sebelumnya fragmentdari fragmentManageritu sendiri secara langsung untuk membuat adapteruntuk mengatur yang baru fragmentdari daftar baru lagi sebagai berikut:

public void setPagerItems(ArrayList<PagerItem> pagerItems) {
    if (mPagerItems != null)
        for (int i = 0; i < mPagerItems.size(); i++) {
            mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
        }
    mPagerItems = pagerItems;
}

5) Dari wadah Activityatau Fragmentjangan inisialisasi ulang adaptor dengan data baru. Atur data baru melalui metode setPagerItemsdengan data baru sebagai berikut:

ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));

mPagerAdapter.setPagerItems(pagerItems);
mPagerAdapter.notifyDataSetChanged();

Saya harap ini membantu.

Sami Eltamawy
sumber
@ Pelanggan apa masalah yang Anda hadapi?
Sami Eltamawy
9

Saya memiliki masalah yang sama dan solusi saya gunakan FragmentPagerAdapterdengan mengesampingkan FragmentPagerAdapter#getItemId(int position):

@Override
public long getItemId(int position) {
    return mPages.get(position).getId();
}

Secara default, metode ini mengembalikan posisi item. Saya kira itu ViewPagermemeriksa apakah itemIdtelah diubah dan membuat ulang halaman hanya jika itu. Tetapi versi itemIdyang tidak diganti mengembalikan posisi yang sama bahkan jika halaman sebenarnya berbeda, dan ViewPager tidak mendefinisikan halaman yang diganti dan harus dibuat ulang.

Untuk menggunakan ini, long id diperlukan untuk setiap halaman. Biasanya ini diharapkan unik, tetapi saya sarankan, untuk kasus ini, hanya berbeda dari nilai sebelumnya untuk halaman yang sama. Jadi, dimungkinkan untuk menggunakan penghitung kontinu dalam adaptor atau bilangan bulat acak (dengan distribusi luas) di sini.

Saya pikir ini lebih konsisten daripada menggunakan Tag of view yang disebutkan sebagai solusi dalam topik ini. Tapi mungkin tidak untuk semua kasus.

atlascoder
sumber
1
Ini. Saya sudah memeriksanya: hanya POSITION_NONE tidak cukup. Terima kasih atas jawaban Anda yang luar biasa! :)
Slava
Fungsi ini bahkan tidak ada di PagerAdapter. Kelas apa ini?
Saket
@ Paket, Anda benar, kelasnya adalahFragmentPagerAdapter
atlascoder
6

Saya menemukan keputusan yang sangat menarik dari masalah ini. Alih-alih menggunakan FragmentPagerAdapter , yang menyimpan semua fragmen dalam memori, kita dapat menggunakan FragmentStatePagerAdapter ( android.support.v4.app.FragmentStatePagerAdapter ), yang memuat ulang fragmen setiap kali, ketika kita memilihnya.

Realisasi kedua adapter itu identik. Jadi, kita hanya perlu mengubah " extended FragmentPagerAdapter " pada " extended FragmentStatePagerAdapter "

Рома Богдан
sumber
Poin baiknya, ini akan membantu orang lain untuk memecahkan masalah memori viewPager yang terkait dengan fragmen
Ashu Kumar
Jawaban yang bagus, ini banyak membantu saya.
Sergio Marani
5

Setelah banyak mencari masalah ini, saya menemukan solusi yang sangat baik yang saya pikir adalah cara yang tepat untuk menyelesaikan masalah ini. Pada dasarnya, instantiateItem hanya dipanggil ketika tampilan instantiated dan tidak pernah lagi kecuali tampilan dihancurkan (ini adalah apa yang terjadi ketika Anda mengganti fungsi getItemPosition untuk mengembalikan POSITION_NONE). Sebaliknya, apa yang ingin Anda lakukan adalah menyimpan tampilan yang dibuat dan memperbaruinya di adaptor, menghasilkan fungsi get sehingga orang lain dapat memperbaruinya, atau fungsi set yang memperbarui adaptor (favorit saya).

Jadi, di MyViewPagerAdapter Anda tambahkan variabel seperti:

private View updatableView;

sebuah di instantiateItem Anda:

 public Object instantiateItem(View collection, int position) {
        updatableView = new TextView(ctx); //My change is here
        view.setText(data.get(position));
        ((ViewPager)collection).addView(view);
        return view;
    }

jadi, dengan cara ini, Anda dapat membuat fungsi yang akan memperbarui tampilan Anda:

public updateText(String txt)
{
    ((TextView)updatableView).setText(txt);
}

Semoga ini membantu!

Jerman
sumber
Saya menyadari bahwa saya tidak mengatur data instantiateItemsehingga pandangan saya tidak diperbarui. Dari jawaban Anda, saya menyadarinya. +1
Phani Rithvij
5

Dua setengah tahun setelah OP mengajukan pertanyaannya, masalah ini masih, yah, masih menjadi masalah. Jelas prioritas Google dalam hal ini tidak terlalu tinggi, jadi daripada mencari perbaikan, saya menemukan solusi. Terobosan besar bagi saya adalah mencari tahu apa penyebab sebenarnya dari masalah itu (lihat jawaban yang diterima di pos ini ). Setelah jelas bahwa masalahnya adalah bahwa setiap halaman aktif tidak di-refresh dengan benar, solusi saya jelas:

Dalam Fragmen saya (halaman):

  • Saya mengambil semua kode yang mengisi formulir keluar dari onCreateView dan meletakkannya dalam fungsi yang disebut PopulateForm yang dapat dipanggil dari mana saja, bukan oleh framework. Fungsi ini mencoba untuk mendapatkan tampilan saat ini menggunakan getView, dan jika itu nol, itu hanya mengembalikan. Sangat penting bahwa PopulateForm hanya berisi kode yang menampilkan - semua kode lain yang membuat pendengar FocusChange dan sejenisnya masih di OnCreate
  • Buat boolean yang dapat digunakan sebagai bendera yang menunjukkan formulir harus dimuat ulang. Milik saya adalah mbReloadForm
  • Override OnResume () untuk memanggil PopulateForm () jika mbReloadForm diatur.

Di Aktivitas saya, tempat saya memuat halaman:

  • Pergi ke halaman 0 sebelum mengubah apa pun. Saya menggunakan FragmentStatePagerAdapter, jadi saya tahu bahwa dua atau tiga halaman paling banyak terpengaruh. Mengubah ke halaman 0 memastikan saya hanya memiliki masalah di halaman 0, 1 dan 2.
  • Sebelum membersihkan daftar lama, ambil ukurannya (). Dengan cara ini Anda tahu berapa banyak halaman yang dipengaruhi oleh bug. Jika> 3, kurangi menjadi 3 - jika Anda menggunakan PagerAdapter yang berbeda, Anda harus melihat berapa banyak halaman yang harus Anda tangani (mungkin semua?)
  • Muat ulang data dan panggil halamanAdapter.notifyDataSetChanged ()
  • Sekarang, untuk setiap halaman yang terpengaruh, lihat apakah halaman tersebut aktif dengan menggunakan pager.getChildAt (i) - ini memberitahu Anda jika Anda memiliki pandangan. Jika demikian, panggil pager.PopulateView (). Jika tidak, atur bendera ReloadForm.

Setelah ini, ketika Anda memuat ulang set halaman kedua, bug masih akan menyebabkan beberapa orang menampilkan data lama. Namun, mereka sekarang akan di-refresh dan Anda akan melihat data baru - pengguna Anda tidak akan tahu halaman itu salah karena penyegaran ini akan terjadi sebelum mereka melihat halaman.

Semoga ini bisa membantu seseorang!

RichardP
sumber
5

Semua solusi ini tidak membantu saya. jadi saya menemukan solusi yang berfungsi: Anda dapat setAdaptersetiap waktu, tetapi itu tidak cukup. Anda harus melakukan ini sebelum mengganti adaptor:

FragmentManager fragmentManager = slideShowPagerAdapter.getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
List<Fragment> fragments = fragmentManager.getFragments();
for (Fragment f : fragments) {
    transaction.remove(f);
}
transaction.commit();

dan setelah ini:

viewPager.setAdapter(adapter);
Mahdi Sempurna
sumber
Terima kasih! Dalam kasus saya, saya menggunakan ViewPagerbagian dalam, jadi diganti slideShowPagerAdapter.getFragmentManager()dengan getChildFragmentManager(). Mungkin getFragmentManager()akan membantu dalam kasus Anda. Saya menggunakan FragmentPagerAdapter, bukan FragmentStatePagerAdapter. Lihat juga stackoverflow.com/a/25994654/2914140 untuk cara meretas.
CoolMind
5

Cara yang jauh lebih mudah: gunakan a FragmentPagerAdapter, dan bungkus tampilan halaman Anda ke dalam fragmen. Mereka diperbarui

alfongj
sumber
5

Terima kasih rui.araujo dan Alvaro Luis Bustamante. Pada awalnya, saya mencoba menggunakan cara rui.araujo, karena itu mudah. Ini berfungsi tetapi ketika data berubah, halaman akan menggambar ulang dengan jelas. Itu buruk jadi saya mencoba menggunakan cara Alvaro Luis Bustamante. Itu sempurna. Ini kodenya:

@Override
protected void onStart() {
    super.onStart();
}

private class TabPagerAdapter extends PagerAdapter {
    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public boolean isViewFromObject(final View view, final Object object) {
        return view.equals(object);
    }

    @Override
    public void destroyItem(final View container, final int position, final Object object) {
        ((ViewPager) container).removeView((View) object);
    }

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final View view = LayoutInflater.from(
                getBaseContext()).inflate(R.layout.activity_approval, null, false);
        container.addView(view);
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        view.setTag(position);
        new ShowContentListTask(listView, position).execute();
        return view;
    }
}

Dan ketika data berubah:

for (int i = 0; i < 4; i++) {
    View view = contentViewPager.findViewWithTag(i);
    if (view != null) {
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        new ShowContentListTask(listView, i).execute();
    }
}
evan.z
sumber
4

Kalau-kalau ada orang yang menggunakan adaptor berbasis FragmentStatePagerAdapter (yang akan membuat ViewPager membuat halaman minimum yang diperlukan untuk tujuan tampilan, paling banyak 2 untuk kasus saya), jawaban @ rui.araujo tentang menimpa getItemPosition di adaptor Anda tidak akan menyebabkan pemborosan yang signifikan, tetapi tetap saja dapat ditingkatkan.

Dalam kode semu:

public int getItemPosition(Object object) {
    YourFragment f = (YourFragment) object;
    YourData d = f.data;
    logger.info("validate item position on page index: " + d.pageNo);

    int dataObjIdx = this.dataPages.indexOf(d);

    if (dataObjIdx < 0 || dataObjIdx != d.pageNo) {
        logger.info("data changed, discard this fragment.");
        return POSITION_NONE;
    }

    return POSITION_UNCHANGED;
}
Jerry Tian
sumber
di dalam ViewPager, cukup mudah untuk mengetahui posisi item item, implementasi yang paling sempurna adalah mengembalikan posisi baru getItemPosition()ketika dataset berubah, dan ViewPager akan tahu mereka berubah atau tidak. Sayangnya, ViewPager tidak melakukannya.
VinceStyling
3

Saya memiliki masalah yang sama di mana saya memiliki empat halaman dan satu halaman memperbarui tampilan pada tiga lainnya. Saya dapat memperbarui widget (SeekBars, TextViews, dll.) Di halaman yang berdekatan dengan halaman saat ini. Dua halaman terakhir akan memiliki widget yang tidak diinisialisasi saat menelepon mTabsAdapter.getItem(position).

Untuk mengatasi masalah saya, saya menggunakan setSelectedPage(index)sebelum menelepon getItem(position). Ini akan membuat Instantiate halaman, memungkinkan saya untuk dapat mengubah nilai dan widget pada setiap halaman.

Setelah semua pembaruan saya akan gunakan setSelectedPage(position)diikuti oleh notifyDataSetChanged().

Anda dapat melihat sedikit kedipan di ListView pada halaman pembaruan utama, tetapi tidak ada yang terlihat. Saya belum mengujinya secara menyeluruh, tetapi itu memecahkan masalah langsung saya.

enKoder
sumber
Hai, saya tertarik pada kode Anda, saya menghadapi masalah yang sama, saya dapat memperbarui fragmen yang berdekatan tetapi fragmen saat ini yang terlihat tidak dapat diperbarui. Saya sangat bingung dengan semua jawaban di sini. bagaimana saya bisa memperbarui tampilan dalam fragmen saat ini yang ditunjukkan oleh adaptor VIewPager
Pankaj Nimgade
3

Saya hanya memposting jawaban ini jika ada orang lain yang merasa berguna. Untuk melakukan hal yang persis sama, saya cukup mengambil kode sumber dari ViewPager dan PagerAdapter dari perpustakaan kompatibilitas dan mengkompilasinya dalam kode saya (Anda perlu memilah semua kesalahan dan mengimpor sendiri, tetapi pasti bisa dilakukan).

Kemudian, di CustomViewPager, buat metode yang disebut updateViewAt (posisi int). Tampilan itu sendiri dapat diperoleh dari mrayems ArrayList didefinisikan dalam kelas ViewPager (Anda perlu mengatur Id untuk tampilan di item instantiate dan membandingkan id ini dengan posisi dalam metode updateViewAt ()). Kemudian Anda dapat memperbarui tampilan sesuai kebutuhan.

Naveen LP
sumber
2

Saya kira, saya punya logika ViewPager.

Jika saya perlu menyegarkan satu set halaman dan menampilkannya berdasarkan dataset baru, saya panggil notifyDataSetChanged () . Kemudian, ViewPager membuat sejumlah panggilan ke getItemPosition () , dengan meneruskan Fragment sebagai Object. Fragmen ini dapat berasal dari dataset lama (yang ingin saya buang) atau dari yang baru (yang ingin saya tampilkan). Jadi, saya mengganti getItemPosition () dan saya harus menentukan apakah Fragment saya berasal dari dataset lama atau dari yang baru.

Dalam kasus saya, saya memiliki tata letak 2-pane dengan daftar item teratas di panel kiri dan tampilan geser (ViewPager) di sebelah kanan. Jadi, saya menyimpan tautan ke item teratas saya saat ini di dalam PagerAdapter saya dan juga di dalam setiap Fragment halaman instantiated. Ketika item teratas yang dipilih dalam daftar berubah, saya menyimpan item teratas baru di PagerAdapter dan memanggil notifyDataSetChanged () . Dan di getItemPosition yang ditimpa () saya membandingkan item teratas dari adaptor saya ke item teratas dari fragmen saya. Dan hanya jika mereka tidak sama, saya mengembalikan POSITION_NONE. Kemudian, PagerAdapter mengembalikan semua fragmen yang telah mengembalikan POSITION_NONE.

CATATAN. Menyimpan id item teratas daripada referensi mungkin merupakan ide yang lebih baik.

Cuplikan kode di bawah ini agak skematis tapi saya mengadaptasinya dari kode yang sebenarnya berfungsi.

public class SomeFragment extends Fragment {
  private TopItem topItem;
}

public class SomePagerAdapter extends FragmentStatePagerAdapter {
  private TopItem topItem;

  public void changeTopItem(TopItem newTopItem) {
    topItem = newTopItem;
    notifyDataSetChanged();
  }

  @Override
  public int getItemPosition(Object object) {
    if (((SomeFragment) object).getTopItemId() != topItem.getId()) {
      return POSITION_NONE;
    }
    return super.getItemPosition(object);
  }
}

Terima kasih untuk semua peneliti sebelumnya!

Stanislav Karakhanov
sumber
2

Kode di bawah ini berfungsi untuk saya.

Buat kelas yang memperluas kelas FragmentPagerAdapter seperti di bawah ini.

public class Adapter extends FragmentPagerAdapter {

private int tabCount;
private Activity mActivity;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
private int container_id;
private ViewGroup container;
private List<Object> object;

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

public Adapter(FragmentManager fm, int numberOfTabs , Activity mA) {
    super(fm);
    mActivity = mA;
    mFragmentManager = fm;
    object = new ArrayList<>();
    mFragmentTags = new HashMap<Integer, String>();
    this.tabCount = numberOfTabs;
}

@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return Fragment0.newInstance(mActivity);
        case 1:
            return Fragment1.newInstance(mActivity);
        case 2:
            return Fragment2.newInstance(mActivity);
        default:
            return null;
    }}


@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Log.e("Already defined","Yes");
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        Log.e("Fragment Tag","" + position + ", " + tag);
        mFragmentTags.put(position, tag);
    }else{
        Log.e("Already defined","No");
    }
    container_id = container.getId();
    this.container = container;
    if(position == 0){
        this.object.add(0,object);
    }else if(position == 1){
        this.object.add(1,object);
    }else if(position == 2){
        this.object.add(2,object);
    }
    return object;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    if (object instanceof Fragment) {
        Log.e("Removed" , String.valueOf(position));
    }
}

@Override
public int getItemPosition (Object object)
{   int index = 0;
    if(this.object.get(0) == object){
        index = 0;
    }else if(this.object.get(1) == object){
        index = 1;
    }else if(this.object.get(2) == object){
        index = 2;
    }else{
        index = -1;
    }
    Log.e("Index" , "..................." + String.valueOf(index));
    if (index == -1)
        return POSITION_NONE;
    else
        return index;
}

public String getFragmentTag(int pos){
    return "android:switcher:"+R.id.pager+":"+pos;
}

public void NotifyDataChange(){
    this.notifyDataSetChanged();
}

public int getcontainerId(){
    return container_id;
}

public ViewGroup getContainer(){
    return this.container;
}

public List<Object> getObject(){
    return this.object;
}

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

Lalu di dalam setiap Fragmen yang Anda buat, buat metode updateFragment. Dalam metode ini Anda mengubah hal-hal yang perlu Anda ubah dalam fragmen. Sebagai contoh dalam kasus saya, Fragment0 berisi GLSurfaceView yang menampilkan objek 3d berdasarkan path ke file .ply, jadi di dalam metode updateFragment saya, saya mengubah path ke file ply ini.

lalu buat instance ViewPager,

viewPager = (ViewPager) findViewById(R.id.pager);

dan contoh Adpater,

adapter = new Adapter(getSupportFragmentManager(), 3, this);

maka lakukan ini,

viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(1);

Kemudian di dalam kelas Anda menginisialisasi kelas Adapter di atas dan membuat viewPager, setiap kali Anda ingin memperbarui salah satu fragmen Anda (dalam kasus kami Fragment0) gunakan yang berikut ini:

adapter.NotifyDataChange();

adapter.destroyItem(adapter.getContainer(), 0, adapter.getObject().get(0)); // destroys page 0 in the viewPager.

fragment0 = (Fragment0) getSupportFragmentManager().findFragmentByTag(adapter.getFragmentTag(0)); // Gets fragment instance used on page 0.

fragment0.updateFragment() method which include the updates on this fragment

adapter.instantiateItem(adapter.getContainer(), 0); // re-initialize page 0.

Solusi ini didasarkan pada teknik yang disarankan oleh Alvaro Luis Bustamante.

Brainnovo
sumber
1

1.Pertama Anda harus menetapkan metode getItemposition di kelas Pageradapter Anda 2. Anda harus membaca posisi Persis dari Tampilan Pager Anda 3. lalu kirim posisi itu sebagai lokasi data yang baru. 4.Tuliskan tombol pembaruan pada pendengar klik di dalam setonPageChange pendengar

kode program itu sedikit saya modifikasi untuk mengatur elemen posisi tertentu saja

public class MyActivity extends Activity {

private ViewPager myViewPager;
private List<String> data;
public int location=0;
public Button updateButton;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    data = new ArrayList<String>();
    data.add("A");
    data.add("B");
    data.add("C");
    data.add("D");
    data.add("E");
    data.add("F");

    myViewPager = (ViewPager) findViewById(R.id.pager);
    myViewPager.setAdapter(new MyViewPagerAdapter(this, data));

      updateButton = (Button) findViewById(R.id.update);

    myViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int i, float v, int i2) {
             //Toast.makeText(MyActivity.this, i+"  Is Selected  "+data.size(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onPageSelected( int i) {
          // here you will get the position of selected page
            final int k = i;
             updateViewPager(k);

        }

        @Override
        public void onPageScrollStateChanged(int i) {

        }
    });
}

private void updateViewPager(final int i) {  
    updateButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            Toast.makeText(MyActivity.this, i+"  Is Selected  "+data.size(), Toast.LENGTH_SHORT).show();
            data.set(i, "Replaced "+i);         
            myViewPager.getAdapter().notifyDataSetChanged();
        }
    });

}

private class MyViewPagerAdapter extends PagerAdapter {

    private List<String> data;
    private Context ctx;

    public MyViewPagerAdapter(Context ctx, List<String> data) {
        this.ctx = ctx;
        this.data = data;
    }

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

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public Object instantiateItem(View collection, int position) {          

        TextView view = new TextView(ctx);
        view.setText(data.get(position));
        ((ViewPager)collection).addView(view);            
        return view;
    }

    @Override
    public void destroyItem(View collection, int position, Object view) {
         ((ViewPager) collection).removeView((View) view);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {
    }

    @Override
    public void startUpdate(View arg0) {
    }

    @Override
    public void finishUpdate(View arg0) {
    }
}
}
Naveen Kumar
sumber
1

apa yang berhasil bagi saya akan terjadi viewPager.getAdapter().notifyDataSetChanged();

dan di adaptor meletakkan kode Anda untuk memperbarui tampilan di dalam getItemPositionseperti itu

@Override
public int getItemPosition(Object object) {

    if (object instanceof YourViewInViewPagerClass) { 
        YourViewInViewPagerClass view = (YourViewInViewPagerClass)object;
        view.setData(data);
    }

    return super.getItemPosition(object);
}

mungkin bukan cara yang paling benar untuk menyelesaikannya tetapi berhasil ( return POSITION_NONEtriknya menyebabkan crash bagi saya jadi bukankah pilihan)

Fonix
sumber
1

Anda dapat memperbarui semua fragmen secara dinamis, Anda dapat melihat dalam tiga langkah.

Di adaptor Anda:

public class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mFragmentTags = new HashMap<Integer, String>();
}

// Returns total number of pages
@Override
public int getCount() {
    return NUM_ITEMS;
}

// Returns the fragment to display for that page
@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return FirstFragment.newInstance();
        case 1:
            return SecondFragment.newInstance();
        case 2:
            return ThirdFragment.newInstance();
        default:
            return null;
    }
}

// Returns the page title for the top indicator
@Override
public CharSequence getPageTitle(int position) {
    return "Page " + position;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        mFragmentTags.put(position, tag);
    }
    return object;
}

public Fragment getFragment(int position) {
    Fragment fragment = null;
    String tag = mFragmentTags.get(position);
    if (tag != null) {
        fragment = mFragmentManager.findFragmentByTag(tag);
    }
    return fragment;
}}

Sekarang dalam aktivitas Anda:

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener{

MyPagerAdapter mAdapterViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ViewPager viewPager = (ViewPager) findViewById(R.id.vpPager);
    mAdapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(mAdapterViewPager);
    viewPager.addOnPageChangeListener(this);
}

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

}

@Override
public void onPageSelected(int position) {

    Fragment fragment = mAdapterViewPager.getFragment(position);
    if (fragment != null) {
        fragment.onResume();
    }
}

@Override
public void onPageScrollStateChanged(int state) {

}}

Akhirnya dalam fragmen Anda, sesuatu seperti itu:

public class YourFragment extends Fragment {

// newInstance constructor for creating fragment with arguments
public static YourFragment newInstance() {

    return new YourFragment();
}

// Store instance variables based on arguments passed
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment, container, false);
}


@Override
public void onResume() {
    super.onResume();

    //to refresh your view
    refresh();

}}

Anda dapat melihat kode lengkap di sini .

Terima kasih Alvaro Luis Bustamante.

Cabezas
sumber
1

Selalu kembali POSITION_NONEadalah hal yang sederhana tetapi sedikit tidak efisien karena itu membangkitkan instantiasi dari semua halaman yang sudah instantiated.

Saya telah membuat perpustakaan ArrayPagerAdapter untuk mengubah item di PagerAdapters secara dinamis.

Secara internal, adaptor perpustakaan ini kembali POSITION_NONEaktifgetItemPosiition() hanya bila diperlukan.

Anda dapat mengubah item secara dinamis seperti mengikuti dengan menggunakan perpustakaan ini.

@Override
protected void onCreate(Bundle savedInstanceState) {
        /** ... **/
    adapter = new MyStatePagerAdapter(getSupportFragmentManager()
                            , new String[]{"1", "2", "3"});
    ((ViewPager)findViewById(R.id.view_pager)).setAdapter(adapter);
     adapter.add("4");
     adapter.remove(0);
}

class MyPagerAdapter extends ArrayViewPagerAdapter<String> {

    public MyPagerAdapter(String[] data) {
        super(data);
    }

    @Override
    public View getView(LayoutInflater inflater, ViewGroup container, String item, int position) {
        View v = inflater.inflate(R.layout.item_page, container, false);
        ((TextView) v.findViewById(R.id.item_txt)).setText(item);
        return v;
    }
}

Perpustakaan Thils juga mendukung halaman yang dibuat oleh Fragmen.

T.Nakama
sumber
1

Ini untuk semua orang seperti saya, yang perlu memperbarui Viewpager dari layanan (atau utas latar belakang lainnya) dan tidak ada proposal yang berhasil: Setelah sedikit pemeriksaan log saya sadari, bahwa metode notifyDataSetChanged () tidak pernah kembali. getItemPosition (Object object) disebut semua ujung di sana tanpa proses lebih lanjut. Kemudian saya temukan di dokumen kelas PagerAdapter induk (tidak dalam dokumen subclass), "Perubahan set data harus terjadi pada utas utama dan harus diakhiri dengan panggilan untuk notifyDataSetChanged ()". Jadi, solusi yang berfungsi dalam hal ini adalah (menggunakan FragmentStatePagerAdapter dan getItemPosition (objek objek) diatur untuk mengembalikan POSITION_NONE):

dan kemudian panggilan untuk notifyDataSetChanged ():

runOnUiThread(new Runnable() {
         @Override
         public void run() {
             pager.getAdapter().notifyDataSetChanged();
         }
     });
Helmwag
sumber
1

Anda dapat menambahkan transformasi pager pada Viewpager seperti ini

myPager.setPageTransformer(true, new MapPagerTransform());

Dalam kode di bawah ini saya mengubah warna tampilan saya saat runtime ketika pager gulir

public class MapPagerTransform implements ViewPager.PageTransformer {


    public void transformPage(View view, float position) {
     LinearLayout  showSelectionLL=(LinearLayout)view.findViewById(R.id.showSelectionLL);

     if (position < 0) {

                showSelectionLL.setBackgroundColor(Color.WHITE);
     }else if (position >0){

                showSelectionLL.setBackgroundColor(Color.WHITE);
     }else {
                showSelectionLL.setBackgroundColor(Color.RED);
     }
   }
}
Akshay dashore
sumber
1

Aku tahu aku terlambat, tapi tetap saja itu bisa membantu seseorang. Saya hanya memperluas jawaban yang diterima dan saya juga menambahkan komentar di atasnya.

baik,

jawabannya sendiri mengatakan itu tidak efisien

jadi untuk membuatnya refresh hanya ketika diperlukan, kamu bisa melakukan ini

private boolean refresh;

public void refreshAdapter(){
    refresh = true;
    notifyDataSetChanged();
}

@Override
public int getItemPosition(@NonNull Object object) {
    if(refresh){
        refresh = false;
        return POSITION_NONE;
    }else{
        return super.getItemPosition(object);
    }
}
contoh
sumber
1

ViewPager tidak dirancang untuk mendukung perubahan tampilan dinamis.

Saya mendapat konfirmasi tentang ini saat mencari bug lain yang terkait dengan ini https://issuetracker.google.com/issues/36956111 dan khususnya https://issuetracker.google.com/issues/36956111#comment56

Pertanyaan ini agak lama, tetapi Google baru-baru ini menyelesaikan masalah ini dengan ViewPager2 . Ini akan memungkinkan untuk mengganti solusi buatan tangan (tidak terawat dan berpotensi buggy) dengan yang standar. Itu juga mencegah menciptakan kembali pandangan yang tidak perlu seperti yang dilakukan beberapa jawaban.

Untuk contoh ViewPager2, Anda dapat memeriksa https://github.com/googlesamples/android-viewpager2

Jika Anda ingin menggunakan ViewPager2, Anda harus menambahkan dependensi berikut dalam file build.gradle Anda:

  dependencies {
     implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
  }

Kemudian Anda dapat mengganti ViewPager Anda di file xml Anda dengan:

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

Setelah itu, Anda perlu mengganti ViewPager dengan ViewPager2 dalam aktivitas Anda

ViewPager2 membutuhkan RecyclerView.Adapter, atau FragmentStateAdapter, dalam kasus Anda itu bisa menjadi RecyclerView.Adapter

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private Context context;
    private ArrayList<String> arrayList = new ArrayList<>();

    public MyAdapter(Context context, ArrayList<String> arrayList) {
        this.context = context;
        this.arrayList = arrayList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.tvName.setText(arrayList.get(position));
    }

    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvName;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tvName);
        }
    }
} 

Jika Anda menggunakan TabLayout, Anda bisa menggunakan TabLayoutMediator:

        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.OnConfigureTabCallback() {
            @Override
            public void onConfigureTab(@NotNull TabLayout.Tab tab, int position) {
                // configure your tab here
                tab.setText(tabs.get(position).getTitle());
            }
        });

        tabLayoutMediator.attach();

Kemudian Anda akan dapat menyegarkan tampilan Anda dengan memodifikasi data adaptor Anda dan memanggil metode notifyDataSetChanged

Yves Delerm
sumber
0

Saya pikir saya telah membuat cara sederhana untuk memberi tahu perubahan set data:

Pertama, ubah sedikit cara fungsi instantiateItem bekerja:

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final View rootView = mInflater.inflate(...,container, false);
        rootView.setTag(position);
        updateView(rootView, position);
        container.addView(rootView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        mViewPager.setObjectForPosition(rootView, position);
        return rootView;
    }

untuk "updateView", isi tampilan dengan semua data yang ingin Anda isi (setText, setBitmapImage, ...).

verifikasi bahwa destroyView berfungsi seperti ini:

    @Override
    public void destroyItem(final ViewGroup container, final int position, final Object obj) {
        final View viewToRemove = (View) obj;
        mViewPager.removeView(viewToRemove);
    }

Sekarang, anggaplah Anda perlu mengubah data, melakukannya, dan kemudian memanggil fungsi berikutnya pada PagerAdapter:

    public void notifyDataSetChanged(final ViewPager viewPager, final NotifyLocation fromPos,
            final NotifyLocation toPos) {
        final int offscreenPageLimit = viewPager.getOffscreenPageLimit();
        final int fromPosInt = fromPos == NotifyLocation.CENTER ? mSelectedPhotoIndex
                : fromPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit
                        : mSelectedPhotoIndex + offscreenPageLimit;
        final int toPosInt = toPos == NotifyLocation.CENTER ? mSelectedPhotoIndex
                : toPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit
                        : mSelectedPhotoIndex + offscreenPageLimit;
        if (fromPosInt <= toPosInt) {
            notifyDataSetChanged();
            for (int i = fromPosInt; i <= toPosInt; ++i) {
                final View pageView = viewPager.findViewWithTag(i);
                mPagerAdapter.updateView(pageView, i);
            }
        }
    }

public enum NotifyLocation {
    MOST_LEFT, CENTER, MOST_RIGHT
}

Misalnya, jika Anda ingin memberi tahu semua tampilan yang ditampilkan oleh viewPager bahwa ada sesuatu yang berubah, Anda dapat menghubungi:

notifyDataSetChanged(mViewPager,NotifyLocation.MOST_LEFT,NotifyLocation.MOST_RIGHT);

Itu dia.

pengembang android
sumber
0

Untuk apa nilainya, pada KitKat + tampaknya adapter.notifyDataSetChanged()sudah cukup untuk menyebabkan tampilan baru muncul, asalkan Anda sudah setOffscreenPageLimitcukup tinggi. Saya bisa mendapatkan perilaku yang diinginkan dengan melakukan viewPager.setOffscreenPageLimit(2).

mszaro
sumber
0

Saya benar-benar menggunakan notifyDataSetChanged()pada ViewPagerdan CirclePageIndicatordan setelah itu saya sebut destroyDrawingCache()di ViewPagerdan bekerja .. Tak satu pun dari solusi lain bekerja untuk saya.

czaku
sumber
Pertanyaan aslinya hampir 2 tahun, saya yakin ada banyak perbedaan dalam API Android sekarang karena jawaban di sini mungkin tidak tepat untuk semua versi API Android.
C0deAttack