Как получить текущий фрагмент, отображаемый на определенной вкладке в viewpager?

Я хочу получить последний фрагмент в backstack, или текущий отображаемый он для меня одинаковый, на tab b_1 . Как вы можете видеть на следующем изображении, у меня есть ViewPager и еще одна внутренняя tab b . Таким образом, отображаются четыре текущих фрагмента.

Вопрос : Как я могу получить экземпляр Fragment 2 ?

Я видел другие решения, но ни один из них не работает для этого сценария.

Аннотация: фрагмент, который нужно вернуть, не является необходимым для размещения в ViewPager. Я мог открыть еще два фрагмента на вкладке.

сценарий

С помощью этого метода я получаю все текущие видимые фрагменты, но не тот, который мне нужен.

 public ArrayList<Fragment> getVisibleFragment() { List<Fragment> fragments = getSupportFragmentManager().getFragments(); ArrayList<Fragment> visibleFragments = new ArrayList<>(); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment != null && fragment.isVisible()) visibleFragments.add(fragment); } } return visibleFragments; } 

Интересный код

activity_main.xml

 <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="fixed" app:tabGravity="fill"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </android.support.design.widget.CoordinatorLayout> 

MainActivity.java

 public class MainActivity extends AppCompatActivity { private static ViewPagerAdapter adapter; private static ViewPager viewPager; private TabLayout tabLayout; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewpager); setupViewPager(); tabLayout = (TabLayout) findViewById(R.id.tabs); tabLayout.setupWithViewPager(viewPager); setupTabIcons(); } private void setupViewPager() { adapter = new ViewPagerAdapter(getSupportFragmentManager()); // Wrap with HostFragment to get separate tabbed nagivation. adapter.addFrag(HostFragment.newInstance(new Fragment1()), null); adapter.addFrag(HostFragment.newInstance(new RootFragment2()), null); adapter.addFrag(HostFragment.newInstance(new Fragment4()), null); viewPager.setAdapter(adapter); viewPager.setOffscreenPageLimit(2); } public void openNewFragment(Fragment fragment) { HostFragment hostFragment = (HostFragment) adapter.getItem(viewPager.getCurrentItem()); hostFragment.replaceFragment(fragment, true); } } 

fragment_host.xml

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/hosted_fragment" android:layout_width="match_parent" android:layout_height="match_parent"/> 

HostFragment.java

 /** * This class implements separate navigation for a tabbed viewpager. * * Based on https://medium.com/@nilan/separate-back-navigation-for- * a-tabbed-view-pager-in-android-459859f607e4#.u96of4m4x */ public class HostFragment extends BackStackFragment { private Fragment fragment; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View view = inflater.inflate(R.layout.fragment_host, container, false); if (fragment != null) { replaceFragment(fragment, false); } return view; } public void replaceFragment(Fragment fragment, boolean addToBackstack) { if (addToBackstack) { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit(); } else { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit(); } } public static HostFragment newInstance(Fragment fragment) { HostFragment hostFragment = new HostFragment(); hostFragment.fragment = fragment; return hostFragment; } public Fragment getFragment() { return fragment; } } 

fragment2_root.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/fragment2_root" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.design.widget.TabLayout android:id="@+id/tab2_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMode="fixed" app:tabGravity="fill"/> <android.support.v4.view.ViewPager android:id="@+id/tab2_viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </LinearLayout> 

RootFragment2.java

 public class RootFragment2 extends Fragment { private ViewPagerAdapter adapter; private ViewPager viewPager; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Inflate the layout for this fragment. View root = inflater.inflate(R.layout.fragment2_root, container, false); viewPager = (ViewPager) root.findViewById(R.id.tab2_viewpager); setupViewPager(viewPager); TabLayout tabLayout = (TabLayout) root.findViewById(R.id.tab2_tabs); tabLayout.setupWithViewPager(viewPager); return root; } private void setupViewPager(ViewPager viewPager) { adapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager()); // Wrap with HostFragment to get separate tabbed nagivation. adapter.addFrag(HostFragment.newInstance(new Fragment2()), null); adapter.addFrag(HostFragment.newInstance(new Fragment3()), null); viewPager.setAdapter(adapter); viewPager.setOffscreenPageLimit(1); } public ViewPagerAdapter getAdapter() { return adapter; } public ViewPager getViewPager() { return viewPager; } } 

    Сначала определите SparseArray в адаптерах ViewPagers , как ViewPagers ниже. В этом массиве мы будем иметь экземпляр фрагментов.

     SparseArray<Fragment> registeredFragments = new SparseArray<>(); 

    И переопределите метод instantiateItem ваших адаптеров.

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

    Также метод Override destroyItem для ваших ViewPagers

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

    И определите новый метод, чтобы получить экземпляр экземпляров ViewPager Fragments .

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

    И, наконец, добавьте в свой ViewPagers :

     viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { // Here's your instance YourFragment fragment =(YourFragment)yourPagerAdapter.getRegisteredFragment(position); } @Override public void onPageScrollStateChanged(int state) { } }); 

    Надеюсь, это поможет вам. Удачи.

    Редактировать: Мне жаль, что я не могу точно понять, что вы планируете делать, но если вам нужно сохранить экземпляр sub-фрагмента (b_1, b_2), вы можете определить способ для своей деятельности, такой как

     public void setCurrentFragment(Fragment fragment){ this.currentFragment = fragment; } 

    И в вашем адаптере пейджера подвид вы можете вызвать этот метод, как показано ниже:

     subViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { // Here's your instance YourFragment fragment =(YourFragment)yourSubPagerAdapter.getRegisteredFragment(position); ((MyActivity)getActivity).setCurrentFragment(fragment); } @Override public void onPageScrollStateChanged(int state) { } }); 

    Таким образом, вы можете сохранить один экземпляр и ваш верхний фрагмент.

    После некоторых комментариев с DEADMC я решил реализовать его с дополнительной памятью, сохранив в списке открытые фрагменты.

    Я объясню свое решение. У меня есть два типа специальных фрагментов, хост и корень . Фрагменты хоста – это те, которые являются инициалами вкладки. Корневые фрагменты – это те, которые содержат ViewPager. В этом случае tab_b имеет корневой фрагмент с внутренним ViewPager.

    иерархия

    Для каждой вкладки это для каждого HostFragment , я добавил fragments списка, чтобы сохранить фрагменты, открытые на этой вкладке. Также метод getCurrentFragment чтобы последний отображался на этой вкладке.

     public class HostFragment extends BackStackFragment { private ArrayList<Fragment> fragments = new ArrayList<>(); public Fragment getCurrentFragment() { return fragments.get(fragments.size() - 1); } 

    Также необходим способ удаления последнего фрагмента, отображаемого на этой вкладке, для поддержания истинного состояния. Кнопка «Назад» должна быть перенаправлена ​​на этот метод.

      public void removeCurrentFragment() { getChildFragmentManager().popBackStack(); fragments.remove(fragments.size() - 1); } 

    Также необходимо изменить предыдущие методы, чтобы вставить новые фрагменты, открытые в список.

      public void replaceFragment(Fragment fragment, boolean addToBackstack) { // NEW: Add new fragment to the list. fragments.add(fragment); if (addToBackstack) { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit(); } else { getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit(); } } public static HostFragment newInstance(Fragment fragment) { HostFragment hostFragment = new HostFragment(); // NEW: Add first fragment to the list. hostFragment.fragments.add(fragment); return hostFragment; } } // HostFragment. 

    RootFragment – это интерфейс, реализованный теми фрагментами, которые содержат ViewPager.

     public interface RootFragment { /** * Opens a new Fragment in the current page of the ViewPager held by this Fragment. * * @param fragment - new Fragment to be opened. */ void openNewFragment(Fragment fragment); /** * Returns the fragment displayed in the current tab of the ViewPager held by this Fragment. */ Fragment getCurrentFragment(); } 

    И тогда реализация будет:

    MainActivity не является фрагментом, но я реализую интерфейс RootFragment для значения.

     public class MainActivity extends AppCompatActivity implements RootFragment { private void setupViewPager() { adapter = new ViewPagerAdapter(getSupportFragmentManager()); // Wrap with HostFragment to get separate tabbed nagivation. adapter.addFrag(HostFragment.newInstance(new Fragment1()), null); adapter.addFrag(new RootFragment2(), null); // This is a Root, not a Host. adapter.addFrag(HostFragment.newInstance(new Fragment4()), null); viewPager.setAdapter(adapter); // 2 because TabLayout has 3 tabs. viewPager.setOffscreenPageLimit(2); } @Override public void openNewFragment(Fragment fragment) { Fragment hosted = adapter.getItem(viewPager.getCurrentItem()); // Replace the fragment of current tab to [fragment]. if (hosted instanceof HostFragment) { ((HostFragment) hosted).replaceFragment(fragment, true); // Spread action to next ViewPager. } else { ((RootFragment) hosted).openNewFragment(fragment); } } @Override public Fragment getCurrentFragment() { Fragment hosted = adapter.getItem(viewPager.getCurrentItem()); // Return current tab's fragment. if (hosted instanceof HostFragment) { return ((HostFragment) hosted).getCurrentFragment(); // Spread action to next ViewPager. } else { return ((RootFragment) hosted).getCurrentFragment(); } } } 

    И RootFragment2

     public class RootFragment2 extends Fragment implements RootFragment { private void setupViewPager(ViewPager viewPager) { adapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager()); // Wrap with HostFragment to get separate tabbed nagivation. adapter.addFrag(HostFragment.newInstance(new Fragment2()), null); adapter.addFrag(HostFragment.newInstance(new Fragment3()), null); viewPager.setAdapter(adapter); // 1 because TabLayout has 2 tabs. viewPager.setOffscreenPageLimit(1); } @Override public void openNewFragment(Fragment fragment) { ((HostFragment) adapter.getItem(viewPager.getCurrentItem())).replaceFragment(fragment, true); } @Override public Fragment getCurrentFragment() { return ((HostFragment) adapter.getItem(viewPager.getCurrentItem())).getCurrentFragment(); } } 

    И тогда мне просто нужно позвонить:

    ((MainActivity) getActivity ()). GetCurrentFragment ();

    Вы можете создать что-то вроде класса CustomFragment который содержит метод getClassName и распространяется от класса Fragment . Затем расширьте все ваши фрагменты, такие как RootFragment2 из класса CustomFragment а не только Fragment .

    Таким образом, вы можете получить фрагмент следующим образом:

     public CustomFragment getNeededFragment(String fragmentName) { List<Fragment> fragments = getSupportFragmentManager().getFragments(); CustomFragment result = null; if (fragments != null) { for (Fragment fragment : fragments) { if (fragment != null && fragment.isVisible()) { try { CustomFragment customFragment = (CustomFragment) customFragment; if (customFragment.getClassName().equals(fragmentName))) result = customFragment; } catch (ClassCastException e) { } } } } return result ; } 

    Я бы сделал что-то вроде этого:

    1 . Создайте такой интерфейс.

     public interface ReturnMyself { Fragment returnMyself(); } 

    2 . Все фрагменты внутри ViewPagers должны реализовать это.

    3 . Добавьте OnPageChangeListener в свой главный VP. Поэтому вы всегда будете знать текущую позицию.

    4 . Добавьте OnPageChangeListener ваш внутренний VP, чтобы вы знали, какой из них есть на экране.

    5 . Добавьте метод к вашему адаптеру (как основному, так и внутреннему), который возвращает ваш фрагмент из списка, переданного ему.

     public ReturnMyself getReturnMyselfAtPosition() 

    6 . Все фрагменты должны возвращать это в returnMyself()

    7 . Фрагмент, который имеет внутренние фрагменты, должен вернуться взамен.

     Fragment returnMyself() { return this.myInnerFragmentAdapter.getReturnMyselfAtPosition().returnMyself(); } 

    8 . От основного фрагмента / активности вы просто звоните.

     this.adapter.getReturnMyselfAtPosition().returnMyself(); 

    И вы получили свой текущий фрагмент.

    Intereting Posts
    Open GL Bad Config Ошибка на Samsung S4 Android SDK Tools 21: Справка по компиляции со вкладкой Как приложение Android может определить, какой магазин установил его? Android: Intent Service с сетевыми библиотеками (дооснащение или волейбол) Получать 3 широковещательных передачи Когда сеть переключается с GPRS на Wi-Fi Почему собственный поток oauth2 для Google требует секретности клиента? Как отобразить размер файла в виде списка с именем файла Показывать только две цифры после десятичной Android ARC-приложение для Chrome, задает размер окон для разных видов деятельности / макетов Идентификация именования Android: нижний регистр с подчеркиванием против верблюда Пользовательский текстовый формат BottomNavigationView поддерживает андроид Как управлять различными задачами, которые должны быть вызваны AsyncTask Picasso Загрузить изображение из файловой системы Каков наилучший способ сохранения адаптера как внутреннего класса деятельности или снаружи? Безопасно ли поддерживать только armeabi-v7a для Android 4 и выше?