wake-up-neo.com

So fügen Sie ein Fragment in einen ViewPager mithilfe eines verschachtelten Fragments hinzu (Android 4.2)

Ich habe ein ViewPager mit drei Fragments, jedes zeigt ein List (oder Grid).

Im neuen Android API level 17 (Jelly Bean 4.2), eines der Features ist Nested Fragments . Die neue Funktionsbeschreibung lautet:

wenn Sie mit ViewPager Fragmente erstellen, die nach links und rechts streichen und einen Großteil des Bildschirmbereichs beanspruchen, können Sie jetzt Fragmente in jede Fragmentseite einfügen.

Wenn ich das richtig verstehe, kann ich jetzt ein ViewPager mit Fragments (zum Beispiel mit einer Schaltfläche im Inneren) erstellen und wenn der Benutzer die Schaltfläche drückt, wird ein anderes Fragment ohne angezeigt Mit dieser neuen Funktion können Sie ViewPager verlieren.

Ich habe meinen Morgen damit verbracht, dies auf verschiedene Arten umzusetzen, aber ich kann es nicht zum Laufen bringen ... Kann jemand ein einfaches Beispiel hinzufügen, wie man das umsetzt?

PS: Ich bin nur daran interessiert, auf diese Weise mit getChildFragmentManager zu lernen, wie es funktioniert.

55
sabadow

Angenommen, Sie haben die richtigen XML-Layouts erstellt. Es ist jetzt sehr einfach, Fragmente in einem ViewPager anzuzeigen, der von einem anderen Fragment gehostet wird.

Folgendes ist ein übergeordnetes Fragment, das untergeordnete Fragmente anzeigt:

class ParentViewPagerFragment : Fragment() {

  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val root = inflater.inflate(R.layout.fragment_parent_viewpager, container, false)

    val viewPager = root.findViewById(R.id.viewPager) as ViewPager
    // Important: Must use the child FragmentManager or you will see side effects.
    viewPager.adapter = MyAdapter(childFragmentManager)

    val tabStrip = root.findViewById<TabLayout>(R.id.pagerTabStrip)
    tabStrip.setupWithViewPager(viewPager)

    return root
  }

  class MyAdapter internal constructor(fm: FragmentManager) : FragmentPagerAdapter(fm) {

    override fun getCount(): Int = 4

    override fun getItem(position: Int): Fragment {
      val args = Bundle().apply { putInt(ChildFragment.POSITION_KEY, position) }
      return ChildFragment.newInstance(args)
    }

    override fun getPageTitle(position: Int): CharSequence = "Tab $position"
  }

  companion object {
    val TAG: String = ParentViewPagerFragment::class.Java.name
  }
}

Es ist wichtig, Fragment.getChildFragmentManager () zu verwenden, wenn der FragmentPagerAdapter instanziiert wird. Beachten Sie auch, dass Sie Fragment.setRetainInstance () nicht für die untergeordneten Fragmente verwenden können, da sonst eine Ausnahme auftritt. Die Importe wurden der Kürze halber weggelassen.

Quellcode finden Sie unter: https://github.com/marcoRS/nested-fragments

100
Marco RS

Edit: Wenn Sie den gesamten Inhalt einer Seite in einem ViewPager ersetzen möchten, können Sie weiterhin verschachtelte Fragmente verwenden, aber einige Änderungen sind erforderlich. Überprüfen Sie das folgende Beispiel (das FragmentActivity, das ViewPager und das PagerAdapter sind die gleichen wie im vorherigen Codeausschnitt):

// this will act as a fragment container, representing one page in the ViewPager
public static class WrapperFragment extends Fragment implements
        ReplaceListener {

    public static WrapperFragment newInstance(int position) {
        WrapperFragment wp = new WrapperFragment();
        Bundle args = new Bundle();
        args.putInt("position", position);
        wp.setArguments(args);
        return wp;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        FrameLayout fl = new FrameLayout(getActivity());
        fl.setId(10000);
        if (getChildFragmentManager().findFragmentByTag("initialTag") == null) {
            InitialInnerFragment iif = new InitialInnerFragment();
            Bundle args = new Bundle();
            args.putInt("position", getArguments().getInt("position"));
            iif.setArguments(args);
            getChildFragmentManager().beginTransaction()
                    .add(10000, iif, "initialTag").commit();
        }
        return fl;
    }

    // required because it seems the getChildFragmentManager only "sees"
    // containers in the View of the parent Fragment.   
    @Override
    public void onReplace(Bundle args) {
        if (getChildFragmentManager().findFragmentByTag("afterTag") == null) {
            InnerFragment iif = new InnerFragment();
            iif.setArguments(args);
            getChildFragmentManager().beginTransaction()
                    .replace(10000, iif, "afterTag").addToBackStack(null)
                    .commit();
        }
    }

}

// the fragment that would initially be in the wrapper fragment
public static class InitialInnerFragment extends Fragment {

    private ReplaceListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mListener = (ReplaceListener) this.getParentFragment();
        LinearLayout ll = new LinearLayout(getActivity());
        Button b = new Button(getActivity());
        b.setGravity(Gravity.CENTER_HORIZONTAL);
        b.setText("Frame " + getArguments().getInt("position"));
        b.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Bundle args = new Bundle();
                args.putInt("positionInner",
                        getArguments().getInt("position"));
                if (mListener != null) {
                    mListener.onReplace(args);
                }
            }
        });
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.addView(b, new LinearLayout.LayoutParams(250,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        return ll;
    }

}

public static class InnerFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        TextView tv = new TextView(getActivity());
        tv.setText("InnerFragment in the outher Fragment with position "
                + getArguments().getInt("positionInner"));
        return tv;
    }

}

public interface ReplaceListener {
    void onReplace(Bundle args);
}

Auf einen Blick funktioniert es, aber es können Probleme auftreten, da ich es nicht zu oft getestet habe.

Kann jemand ein einfaches Beispiel zeigen, wie das geht?

Die Verwendung verschachtelter Fragmente scheint recht einfach zu sein. Bis Commonsware ein ausführlicheres Beispiel enthält, können Sie den folgenden Code ausprobieren:

public class NestedFragments extends FragmentActivity {

    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        ViewPager vp = new ViewPager(this);
        vp.setId(5000);
        vp.setAdapter(new MyAdapter(getSupportFragmentManager()));
        setContentView(vp);
    }

    private static class MyAdapter extends FragmentPagerAdapter {

        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return WrapperFragment.newInstance(position);
        }

        @Override
        public int getCount() {
            return 8;
        }
    }

    public static class WrapperFragment extends Fragment {

        public static WrapperFragment newInstance(int position) {
            WrapperFragment wp = new WrapperFragment();
            Bundle args = new Bundle();
            args.putInt("position", position);
            wp.setArguments(args);
            return wp;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            LinearLayout ll = new LinearLayout(getActivity());
            FrameLayout innerFragContainer = new FrameLayout(getActivity());
            innerFragContainer.setId(1111);
            Button b = new Button(getActivity());
            b.setText("Frame " + getArguments().getInt("position"));
            b.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    InnerFragment innerFragment = new InnerFragment();
                    Bundle args = new Bundle();
                    args.putInt("positionInner",
                            getArguments().getInt("position"));
                    innerFragment.setArguments(args);
                    FragmentTransaction transaction = getChildFragmentManager()
                            .beginTransaction();
                    transaction.add(1111, innerFragment).commit();
                }
            });
            ll.setOrientation(LinearLayout.VERTICAL);
            ll.addView(b, new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT));
            ll.addView(innerFragContainer, new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.MATCH_PARENT));
            return ll;
        }

    }

    public static class InnerFragment extends Fragment {

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            TextView tv = new TextView(getActivity());
            tv.setText("InnerFragment in the outher Fragment with position "
                    + getArguments().getInt("positionInner"));
            return tv;
        }

    }

}

Ich war faul und habe alles in Code geschrieben, aber ich bin sicher, dass es mit aufgeblasenen XML-Layouts funktionieren kann.

12
Luksprog

Ich habe einen ViewPager mit 3 Elementen und 2 Unterelementen für Index 2 und 3 erstellt und hier, was ich tun wollte.

enter image description here

Ich habe dies mit Hilfe der vorherigen Fragen und Antworten von StackOverFlow implementiert und hier ist der Link.

ViewPagerChildFragments

6
Rukmal Dias