web-dev-qa-db-ja.com

PagerAdapter.notifyDataSetChangedはフラグメントを更新しません

私のActivityにはViewPagerが含まれており、Adapterを拡張するカスタムFragmentStatePagerAdapterです。 ViewPagerには3つのフラグメントが含まれます

ViewPagerからフラグメントを削除するコード

MainActivity

public void deleteElement(){
    final int currentItem = mViewPager.getCurrentItem();
    mPagerAdapter.removeItem(currentItem);
    mPagerAdapter.notifyDataSetChanged();
}

CustomPagerAdapter

private ArrayList<Item> data;
public void removeItem(int index){
        data.remove(index);
}

中間のFragment(インデックス1)を削除する場合:

  • dataから正しいitemを削除しています。
  • 問題は、i(i推測)Fragment 3がnotifyDataSetChangedの後に削除され、現在のFragmentはまだユーザーが見たフラグメントであり、ロードされているデータはSavedInstanceバンドル

そのため、ユーザーが削除しようとしたのと同じFragmentが表示されるという最終結果は、彼にとってはちょっと残念です。

アイデア?

*****[〜#〜] edit [〜#〜]******

ViewPager2機能 のように思われる

17
royB

この質問は少し古いことは知っていますが、Googleが最近この問題を ViewPager2 で解決したことを知るのは興味深いかもしれません。例を参照してください here

まず、build.gradleファイル内の次の依存関係:

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

これで、xmlファイルのViewPagerを次のように置き換えることができます。

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

次に、アクティビティでViewPagerをViewPager2に置き換える必要があります。

ViewPager2には、RecycleView.AdapterまたはFragmentStateAdapterが必要です。

_    public class TabAdapter extends FragmentStateAdapter {
        private final List<Tab> tabs;

        public TabAdapter(@NonNull FragmentManager fm, List<Tab> tabs, Lifecycle lifecycle) {
            super(fm, lifecycle);

            this.tabs = tabs;
        }

        @NonNull
        @Override
        public Fragment createFragment(int position) {
            //create your fragment here
        }

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

        @Override
        public long getItemId(int position) {
            // use a distinct id for each item to allow the adapter to see the changes
        }
    }
_

TabLayoutを使用していた場合は、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();
_

データを削除するには、コレクションからアイテムを削除した後、notifyDataSetChanged()メソッドを呼び出すか、削除されたアイテムの位置でnotifyItemRemoved()を呼び出します。

1
Yves Delerm

これを追加してみてください:

private class MyPagerAdapter extends FragmentStatePagerAdapter {

//... your existing code

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

}
28
kelvincer

PagerAdapter#getItemPositionを実装する以外に選択肢はありません。 ViewPagerがその位置を更新する方法を決定する正確な方法であるソースを見ると、notifyDataSetChangedの後に新しいフラグメントを追加するか、無効なフラグメントをドロップします。それほど難しくないはずです。渡されたフラグメントの状態にアクセスするだけでよく、また、順序を保持するアクティビティのマスター状態にアクセスする必要があります。

また、各フラグメントの順序を変更できるため、getItemIdを実装して各フラグメントの一貫したIDを返す必要があります。

これが、写真のViewPagerでの処理方法です。

    private inner class PhotoPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
    override fun getItem(position: Int): PhotoViewFragment {
        // getItem is called to instantiate the fragment for the given page.
        return PhotoViewFragment.newInstance(position, [email protected][position])
    }

    override fun getItemId(position: Int): Long {
        return [email protected][position].ID!!.hashCode().toLong()
    }

    override fun getItemPosition(`object`: Any): Int {
        val frag = `object` as PhotoViewFragment
        val idx = [email protected] { ph -> ph.ID == frag.dataBinding.photo.ID }
        return if (idx >= 0) idx else PagerAdapter.POSITION_NONE
    }

    override fun getCount(): Int {
        return [email protected]
    }
}
5
androidguy

FragmentStatePagerAdapterの代わりにFragmentPagerAdapterの使用を試みることができます。事は、私もこの問題に遭遇したことであり、それは私を助けた。

0

最初にアダプタをnullに設定してから、元に戻す必要があります。

int currentPosition = mViewPager.getCurrentItem();
mPagerAdapter.notifyDataSetChanged();
mViewPager.setAdapter(null);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.setCurrentItem(currentPosition);
0
Matjaz Kristl