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

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

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

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

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

scenario

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

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.

Hierarchy

для каждая вкладка, это, для каждого 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();

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