it-swarm.com.de

Wie wird das aktuelle Fragment in einer bestimmten Registerkarte eines Viewpagers angezeigt?

Ich möchte das letzte Fragment im Backstack erhalten, oder der angezeigte Strom ist für mich derselbe, im tab b_1. Wie Sie im folgenden Bild sehen können, habe ich einen ViewPager und einen weiteren inneren tab b. Somit werden vier aktuelle Fragmente angezeigt.

Frage: Wie bekomme ich die Fragment 2-Instanz?

Ich habe andere Lösungen gesehen, aber keine funktioniert für dieses Szenario.

Annotation: Das zurückzugebende Fragment ist nicht erforderlich, wenn es im ViewPager gehostet wird. Ich kann zwei weitere Fragmente in einem Tab geöffnet haben.

 scenario

Mit dieser Methode bekomme ich alle aktuellen sichtbaren Fragmente, aber nicht das, was ich will.

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

Einige interessante Code

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>

Hauptaktivität.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

Definieren Sie zunächst eine SparseArray in Ihren ViewPagers'-Adaptern wie unten. In diesem Array halten wir die Instanz von Fragmenten.

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

Überschreiben Sie die instantiateItem-Methode Ihrer Adapter.

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

Überschreiben Sie auch die destroyItem-Methode Ihrer ViewPagers.

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

Definieren Sie eine neue Methode, um Ihre ViewPagerFragments-Instanz abzurufen.

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

Fügen Sie schließlich eine PageChangeListener zu Ihrer ViewPagers hinzu:

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

    }
});

Ich hoffe das wird dir helfen. Viel Glück.

Edit: Es tut mir leid, dass ich nicht genau verstehen kann, was Sie vorhaben. Wenn Sie jedoch die Unterfragment-Instanz (b_1, b_2) beibehalten möchten, können Sie eine Methode für Ihre Aktivität definieren, z

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

und in Ihrem Sub-View-Pager-Adapter können Sie diese Methode wie folgt aufrufen:

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

    }
});

Auf diese Weise können Sie eine Instanz und Ihr oberstes Fragment behalten.

29
savepopulation

Nach einigen Kommentaren mit DEADMC entschied ich mich, es mit zusätzlichem Speicher zu implementieren und die offenen Fragmente in einer Liste zu speichern.

Ich erkläre meine Lösung. Ich habe zwei Arten von speziellen Fragmenten, Host und root. Host-Fragmente sind diejenigen, die das Init eines Tabs sind. Wurzelfragmente sind diejenigen, die einen ViewPager enthalten. In diesem Szenario verfügt tab_b über ein Stammfragment mit einem inneren ViewPager.

 Hierarchy

Für jede Registerkarte ist dies für jedes HostFragment eine Liste fragments, um die in dieser Registerkarte geöffneten Fragmente zu speichern. Auch eine Methode getCurrentFragment, um das letzte auf dieser Registerkarte anzuzeigen.

public class HostFragment extends BackStackFragment {

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

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

Es ist auch eine Methode erforderlich, um das letzte auf dieser Registerkarte angezeigte Fragment zu entfernen, um den Status "True" zu erhalten. Die Zurück-Schaltfläche muss zu dieser Methode umgeleitet werden.

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

Auch müssen frühere Methoden geändert werden, um die neuen Fragmente in die Liste einzufügen.

    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 ist eine von diesen Fragmenten implementierte Schnittstelle, die einen ViewPager enthält.

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

Und dann wäre die Implementierung:

MainActivity ist kein Fragment, aber ich implementiere die RootFragment - Schnittstelle für Bedeutung.

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

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

Und dann muss ich einfach anrufen:

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

3
Santiago Gil

Sie können etwas wie CustomFragment-Klasse erstellen, die die getClassName-Methode enthält und von Fragment-Klasse ausgeht. Erweitern Sie dann alle Ihre Fragmente wie RootFragment2 aus der Klasse CustomFragment und nicht nur aus Fragment.

So kannst du Fragment wie folgt bekommen:

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

Ich würde so etwas machen:

1 . Erstellen Sie eine Schnittstelle wie diese.

public interface ReturnMyself {
    Fragment returnMyself();
}

2 . Alle Fragmente in ViewPagers sollten dieses implementieren.

3 . Fügen Sie Ihrem Haupt-VP OnPageChangeListener hinzu. So kennen Sie immer die aktuelle Position.

4 . Fügen Sie OnPageChangeListener Ihren inneren VP (s) hinzu, damit Sie wissen, welcher auf dem Bildschirm angezeigt wird.

5 . Fügen Sie Ihrem Adapter eine Methode hinzu (Haupt- und Innenadapter), die Ihr Fragment aus der an ihn übergebenen Liste zurückgibt.

public ReturnMyself getReturnMyselfAtPosition()

6 . Alle Fragmente sollten dies in returnMyself() zurückgeben.

7 . Fragment, das innere Fragmente hat, sollte so etwas in returnMyself zurückgeben.

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

8 . Vom Hauptfragment/der Aktivität rufen Sie einfach an.

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

Und du hast dein aktuelles Fragment.