Как получить текущий фрагмент, отображаемый на определенной вкладке 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;
}
}
4 ответов
определить SparseArray
в своем ', как показано ниже. В этом массиве мы будем держать экземпляр фрагментов.
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;
}
Также Переопределить 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);
}
и, наконец, установите add a PageChangeListener
на 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) {
}
});
я надеюсь, что это будет помочь тебе. Удача.
Edit: извините, я не могу понять, что именно вы планируете делать, но если вам нужно сохранить экземпляр sub fragment (b_1, b_2), вы можете определить метод для своей деятельности, такой как
public void setCurrentFragment(Fragment fragment){
this.currentFragment = fragment;
}
и в адаптере вашего sub view pager вы можете вызвать этот метод, как показано ниже:
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 я решил реализовать его с дополнительной памятью, сохранив в списке открытые фрагменты.
объясняю свое решение. Я hve два типа специальных фрагментов, хоста и root. Фрагменты хоста-это те, которые являются инициализацией вкладки. Корневые фрагменты-это те, которые содержат 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);
}
также необходим метод удаления последнего фрагмента, отображаемого на этой вкладке, Для поддержания истинного состояния. Кнопка Back должна быть перенаправлена на этот метод.
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
вашему главному вице-президенту. Так вы всегда будете знать текущее положение.
4. Добавить OnPageChangeListener
ваш внутренний (ы) VP, чтобы вы знали, какой из них есть на экране.
5. Добавить метод ваш адаптер (как основной, так и внутренний), который возвращает ваш фрагмент из переданного ему списка.
public ReturnMyself getReturnMyselfAtPosition()
6. Все фрагменты должны вернуть это в returnMyself()
7. Фрагмент внутренней фрагменты должны вернуться в returnMyself что-то вроде.
Fragment returnMyself() {
return this.myInnerFragmentAdapter.getReturnMyselfAtPosition().returnMyself();
}
8. Из основного фрагмента / действия вы просто вызываете.
this.adapter.getReturnMyselfAtPosition().returnMyself();
и вы получили свой текущий фрагмент.