Как добавить фрагмент внутри ViewPager с помощью вложенного фрагмента (Android 4.2)

у меня есть ViewPager три Fragments, каждый показывает List (или Grid).

новый Android API level 17 (Jelly Bean 4.2), одна из функций -Вложенные Фрагменты. Новое описание функциональности гласит:

если вы используете ViewPager для создания фрагментов, проведите пальцем влево и вправо и потребляйте большую часть пространства экрана, Теперь вы можете вставлять фрагменты на каждой странице фрагмента.

Итак, если я понимаю правильно, теперь я могу создать ViewPager с Fragments (с кнопкой внутри, например) внутри, и когда пользователь нажимает кнопку показать другой Fragment не потерять ViewPager используя эту новую функцию.

я потратил утро, пытаясь реализовать это несколькими способами, но я не могу заставить его работать... Может ли кто-нибудь добавить простой пример того, как это реализовать?

PS: меня интересует только это, с getChildFragmentManager чтобы узнать, как работает.

3 ответов


предполагая, что вы создали правильные макеты xml. Теперь очень просто отображать фрагменты в ViewPager, который размещается другим фрагментом.

код выглядит примерно так в Родительском фрагменте:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_parent, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewPager);
        mViewPager.setAdapter(new MyAdapter(getChildFragmentManager()));
    }

    public static class MyAdapter extends FragmentPagerAdapter {

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

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

        @Override
        public Fragment getItem(int position) {
            Bundle args = new Bundle();
            args.putInt(TextViewFragment.POSITION_KEY, position);
            return TextViewFragment.newInstance(args);
        }
    }

важно использовать фрагмент.getChildFragmentManager () при создании экземпляра FragmentPagerAdapter. Также обратите внимание, что вы не можете использовать фрагмент.setRetainInstance() на фрагментах детей или вы получите исключение.

исходный код можно найти на: https://github.com/marcoRS/nested-fragments


Edit: Если вы хотите заменить все содержимое страницы в ViewPager вы все еще можете использовать вложенные фрагменты, но требуются некоторые изменения. Проверьте образец ниже (FragmentActivity установка ViewPager и PagerAdapter такие же, как и предыдущий фрагмент кода):

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

при быстром взгляде это работает, но проблемы могут возникнуть, поскольку я не тестировал его много.

может кто-нибудь показать простой пример того, как это сделать это?

использование вложенных фрагментов кажется довольно простым, пока Commonsware не поставляется с более подробным образцом, вы можете попробовать код ниже:

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

    }

}

Я был ленив, и сделал все в коде, но я уверен, что он может работать с завышенными XML макеты.


Я создал ViewPager с 3 элементами и 2 подэлементами для индекса 2 и 3 и вот что я хотел сделать..

enter image description here

я реализовал это с помощью предыдущих вопросов и ответов от StackOverFlow, и вот ссылка.

ViewPagerChildFragments