0
MyFragment currentFragment = (MyFragment) getSupportFragmentManager()
                                   .findFragmentByTag("f"+pagerMainAdapter.getItemId(0));
currentFragment.testRun("Hello world");

I'm trying to Migrate from ViewPager to ViewPager2 and and I don't know how to get fragment in ViewPager2.

Zain
  • 37,492
  • 7
  • 60
  • 84

1 Answers1

1

To get the current fragment from ViewPager2:

The ViewPager2 has getCurrentItem() which returns the current page number So, we need to link each page fragment to the corresponding page number.

But we can get a ViewPager2 fragment by its id (item id), so the first step is to have page Ids that equals to the corresponding position, to do so override getItemId in the ViewPager2 FragmentStateAdapter.

@Override
public long getItemId(int position) {
    return position;
}

Then to get the current fragment:

int pageId = viewpager.getCurrentItem();

MyFragment currentFragment = (MyFragment) getSupportFragmentManager()
                                              .findFragmentByTag("f" + pageId);

EDIT:

Apart from the question, getting the viewPager fragment using "f$id" can be discontinued some day by Google in internal APIs; so you should use another way for that; here is a one that can be used in API 24+:

Using newInstance page fragment pattern, you can set some argument in the viewPager page fragment, assuming viewPager fragment is PagerFragment:

Argument constant:

public static final String POSITION = "POSITION";

Adapter:

class ViewPagerFragmentAdapter extends FragmentStateAdapter {
    
    ....

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return PagerFragment.newInstance(position);
    }

}

PageFragment:

public class PagerFragment extends Fragment {

    public static Fragment newInstance(int position) {
        PagerFragment fragment = new PagerFragment();
        Bundle args = new Bundle();
        args.putInt(POSITION, position);
        fragment.setArguments(args);
        return fragment;
    }
}

And to get a fragment of a certain viewPager item:

int id = pagerMainAdapter.getItemId(0); // id of your ViewPager that you need to get the corresponding PageFragment

    Optional<Fragment> optionalFragment =
            getSupportFragmentManager().getFragments().stream()
                    .filter(it -> it instanceof PagerFragment && it.getArguments() != null && it.getArguments().getInt(POSITION) == id)
                    .findFirst();

optionalFragment.ifPresent(fragment -> {
    // This is your needed PageFragment
});
Zain
  • 37,492
  • 7
  • 60
  • 84
  • This currently works, but is a kludge at best. It only works because ViewPager2 **internally** sets the fragment tags to `"f" + itemId` when they are added to the fragment manager. So if Google decides to change how that works in a future release, it will break your code. Also, would have been nice if that detail was included in the OP and/or answer. – zen_of_kermit Mar 30 '22 at 21:53
  • @zen_of_kermit absolutely agreed; just a little hint; it's a part of the [`FragmentStateAdapter`](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java#351) implementation.. Let me check if this could be enhanced reliably – Zain Mar 30 '22 at 22:27
  • Don't need a hint, I looked it up and that's why I wrote **internally**. Definitely not obvious why you both have the "f" prefix without looking at the open source code. – zen_of_kermit Mar 31 '22 at 00:10
  • How difficult is it for Google to add a simple getFragmentByPosition method. internally there is this mFragmentmap. I mean Android SDK is so utterly stupidly build. simple things arent possible or require some kind of hacky reflection – Gillis Haasnoot Aug 30 '23 at 09:55