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