web-dev-qa-db-fra.com

Comment obtenir le fragment actuel affiché dans un onglet spécifique d'un viewpager?

Je veux obtenir le dernier fragment dans le stock, ou le courant affiché est le même pour moi, dans le tab b_1. Comme vous pouvez le voir dans l'image suivante, j'ai un ViewPager et un autre tab b intérieur. Ainsi, quatre fragments actuels sont affichés.

Question: Comment puis-je obtenir l'instance Fragment 2?

J'ai vu une autre solution, mais aucune ne fonctionne pour ce scénario.

Annotation: Le fragment à renvoyer n'est pas nécessairement hébergé dans ViewPager. J'aurais pu ouvrir deux autres fragments dans un onglet.

 scenario

Avec cette méthode, je récupère tous les fragments visibles actuels, mais pas celui que je souhaite.

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;
}

Un code intéressant

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;
    }
}
18
Santiago Gil

Définissez d’abord une SparseArray dans votre ViewPagers 'comme ci-dessous. Dans ce tableau, nous allons tenir l'instance de fragments.

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

Et remplacez la méthode instantiateItem de vos adaptateurs.

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

Remplacez également la méthode destroyItem de votre ViewPagers

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

Et définissez une nouvelle méthode pour obtenir votre instance ViewPagerFragments.

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

Et finalement définissez ajouter une PageChangeListener à votre 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) {

    }
});

J'espère que ça va vous aider. Bonne chance.

Edit: je suis désolé, je ne comprends pas exactement ce que vous envisagez de faire, mais si vous devez conserver une instance de sous-fragment (b_1, b_2), vous pouvez définir une méthode pour votre activité telle

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

et dans l'adaptateur de votre téléavertisseur, vous pouvez appeler cette méthode comme ci-dessous:

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) {

    }
});

De cette façon, vous pouvez conserver une instance et votre fragment supérieur.

29
savepopulation

Après quelques commentaires avec DEADMC, j'ai décidé de l'implémenter avec de la mémoire supplémentaire, en enregistrant dans une liste les fragments ouverts.

J'explique ma solution. J'ai deux types de fragments spéciaux, Host et root. Les fragments d'hôtes sont ceux qui sont l'init d'un onglet. Les fragments de racine sont ceux qui contiennent un ViewPager. Dans ce scénario, tab_b possède un fragment de racine avec un ViewPager interne.

 Hierarchy

Pour chaque onglet, c’est, pour chaque HostFragment, j’ai ajouté une liste fragments afin de sauvegarder les fragments ouverts dans cet onglet. Également une méthode getCurrentFragment pour obtenir le dernier affiché dans cet onglet.

public class HostFragment extends BackStackFragment {

    private ArrayList<Fragment> fragments = new ArrayList<>();

    public Fragment getCurrentFragment() {
        return fragments.get(fragments.size() - 1);
    }

De plus, une méthode pour supprimer le dernier fragment affiché dans cet onglet est nécessaire pour conserver un état vrai. Le bouton Précédent doit être redirigé vers cette méthode.

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

Les méthodes précédentes doivent également être modifiées pour insérer les nouveaux fragments ouverts dans la liste.

    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 est une interface implémentée par ces fragments qui contient un 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();
}

Et puis, la mise en œuvre serait:

MainActivity n'est pas un fragment, mais j'implémente l'interface RootFragment pour la signification.

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();
        }
    }
}

et 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();
    }
}

Et puis, j'ai juste besoin d'appeler:

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

3
Santiago Gil

Vous pouvez créer quelque chose comme la classe CustomFragment qui contient la méthode getClassName et qui s'étend de la classe Fragment. Étendez ensuite tous vos fragments tels que RootFragment2 à partir de CustomFragment classe au lieu de simplement Fragment.

Ainsi, vous pouvez obtenir un fragment comme ceci:

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 ;
}
0
DEADMC

Je ferais quelque chose comme ça:

1 . Créez une interface comme celle-ci.

public interface ReturnMyself {
    Fragment returnMyself();
}

2 . Tous les fragments à l'intérieur de ViewPagers doivent implémenter celui-ci.

3 . Ajoutez OnPageChangeListener à votre vice-président principal. Donc, vous saurez toujours la position actuelle.

4 . Ajoutez OnPageChangeListener votre (s) VP interne (s) afin de savoir lequel est affiché à l'écran.

5 . Ajoutez une méthode à votre adaptateur (principal et interne) qui renvoie votre fragment de la liste qui lui a été transmise.

public ReturnMyself getReturnMyselfAtPosition()

6 . Tous les fragments doivent renvoyer ceci en returnMyself()

7 . Un fragment qui a des fragments intérieurs devrait retourner en retour quelque chose comme moi.

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

8 . Du fragment principal/activité que vous venez d'appeler.

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

Et vous avez votre fragment actuel.

0