Intereting Posts
Как получить следующий номер версии в SVN Создание Google TV AVD на окнах, не отвлекающих системный образ x86 Кросс-платформенная библиотека для связи между C ++ и платформенным кодом (iOS, Android) Я не могу изменить InputType для EditText после того, как я установил его в TYPE_NULL Интеграция времени выполнения Skype в существующем приложении Android RecyclerView прогностические анимации элементов не работают (ПОЯВЛЕНИЕ) Правильный способ установки сертификата PEM на Android Почему этот логический метод использует неправильный путь возврата? Android-приложение использует фотографию для списка друзей Лучшая практика для закругленных прямоугольников в OpenGL ES Запуск Android Studio на Windows 7 не удался, Android SDK не найден Определить тип шаблона регулярного выражения Почему отражение замедляет Android-телефон Анализ с ошибкой jsoup throws (NetworkOnMainThreadException) Как протестировать IntentService с помощью Robolectric?

Как получить текущий фрагмент, отображаемый на определенной вкладке в 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(); 

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