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

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

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

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

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

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

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

 CommonsWare14 нояб. 2012 г., 14:37
Я буду работать над образцом для этого в начале следующей недели. Если никто не вмешался с ответом к тому времени, япостараюсь опубликовать что-то в это время.
 sabadow14 нояб. 2012 г., 16:01
Спасибо @CommonsWare

Ответы на вопрос(3)

Решение Вопроса

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

Ниже представлен родительский фрагмент, который отображает дочерние фрагменты:

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

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

Исходный код можно найти по адресу: https://github.com/marcoRS/nested-fragmentsI»

 straya16 нояб. 2012 г., 08:10
Обнаружил, что мой FragmentPagerAdapter реализовал свой собственный метод isViewObject, который не былЭто проблема перед вложением ViewPager в его собственный фрагмент, после удаления я теперь вижу страницы :) Потянул ваш код и запустил его, чтобы повысить мою уверенность и желание заставить это работать - так что спасибо Марко!
 straya21 нояб. 2012 г., 03:11
@ Adam I 'я уже сделал это, конечно;) Мое исправление было таким, как я описал выше.
 Muhammed Refaat20 апр. 2014 г., 11:08
 Lion78905 мар. 2014 г., 02:51
У кого-нибудь есть полный код? Искать пример этого очень сложно найти ...
 Adam20 нояб. 2012 г., 23:12
@straya Вам нужно заменить библиотеку поддержки в проекте ABS на последнюю (v11), и она должна работать.
 Marco RS16 нояб. 2012 г., 07:16
Привет, Страя, это может быть проблемой, но яЯ не уверен. Я обновил мой пример кода github, добавив в него PagerTabStrip, который похож на ViewPagerIndicator и, кажется, работает нормально.
 Marco RS18 апр. 2014 г., 02:30
Я думаю, что ошибка может быть связана с ошибкой в самом фрагменте, а не из-за вложенности.
 Ruchira Randana14 апр. 2015 г., 13:25
Спасибо Марко. Помог мне исправить мою ошибку !!!
 c-an02 февр. 2019 г., 06:36
Где сделалTextViewFragment от???
 Marco RS16 нояб. 2012 г., 06:20
Привет страя Я проверил мой пример с SherlockFragments и не увидел ошибку. Какую ошибку вы видите?
 Umair14 сент. 2016 г., 22:18
С этими линиями кодовViewPager mViewPager = (ViewPager) view.findViewById (R.id.viewPager); mViewPager.setAdapter (новый MyAdapter (getChildFragmentManager ())); '    Как я могу принести различные макеты в пейджере
 Muhammed Refaat17 апр. 2014 г., 15:53
@ Марко, я могуЭто невозможно из-за того, что возникает исключение при встрече первого элемента при чтении XML-файла первого фрагмента. У вас есть представление об этом? заранее спасибо.
 Muhammed Refaat20 апр. 2014 г., 09:17
@ Марко это дает мнеError Inflating Class, если вам нужна дополнительная иллюстрация, я могу задать вопрос и упомянуть вас в нем.
 straya16 нояб. 2012 г., 06:35
Эй, яМы также получили Android-ViewPagerIndicator. ViewPager и ViewPagerIndicator отображаются (у меня есть TextView над ViewPager над его фрагментом, поэтому я вижу, что этот фрагмент отображается), но ViewPager 'Дочерние фрагменты (предоставляемые через FragmentPagerAdapter) не отображаются. Я могу перемещаться между страницами, обновления индикатора, но не дочерние фрагменты.
 Marco RS04 февр. 2019 г., 01:10
@ChanjungKim I 'Мы обновили образец. Полный код можно найти по ссылке репо выше.
 Umair14 сент. 2016 г., 22:17
@Marco, я относительно новичок в Android и, в частности, во фрагментах, я не могу реализовать пользовательские макеты XML в другой позиции адаптера, не могли бы вы рассказать, как объединить различные макеты с дочерними фрагментами.
 straya16 нояб. 2012 г., 05:58
При этом возникают проблемы (фрагмент, содержащий ViewPager, то есть) с SherlockFragments и support.v4 release11, содержимое ViewPager устанавливается через адаптер, однако дочерние фрагменты не отображаются :(

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

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

ViewPagerChildFragments

 Luke Allison25 янв. 2016 г., 06:33
Кому-нибудь удалось исправить ошибку с помощью этого кода, которая вызывает сбой приложения при изменении ориентации?
 Luke Allison21 янв. 2016 г., 08:05
В этом коде есть некоторые ошибки, такие как сбой при изменении ориентации. Вы когда-нибудь исправляли их?

Редактировать: Если вы хотите заменить все содержимое страницы в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.

 sabadow14 нояб. 2012 г., 16:56
Большое спасибо, яm пытается и рефакторинг для использования с файлами макета XML и, кажется, работает нормально;)
 Luksprog07 мар. 2013 г., 09:12
@Herry Пожалуйста, опубликуйте новый вопрос, добавив связанный код и четко объяснив, в чем проблема.
 Herry07 мар. 2013 г., 09:38
@Luksprog спасибо за предложение, я только что решил свою проблему.
 sabadow14 нояб. 2012 г., 17:38
Я думаю, что там, где вы используетеtransaction.add(1111, innerFragment).commit(); следует использоватьreplace метод, потому что каждый раз, когда кнопка нажата добавить в иерархию макет. Также я реорганизовал пример использования XML Layouts и попытался изменить его на новый.все содержание страницы. Но я не могЯ сделал это еще всегдаButton Оставайся наверху. Любое предложение?
 Luksprog14 нояб. 2012 г., 22:18
@sabadow я использовалadd В качестве примера вы могли бы использоватьreplace это соответствует вашим потребностям. Кнопка остается там в моем образце, потому чтоreplace(или жеadd) метод неt удалить существующие виды из контейнера (установить высотуinnerFragContainer вWRAP_CONTENT и ты'увидим, что существующие виды остаются с добавлением нового фрагмента внизу). И будет сложно сделать то, что тыпытаемся сделать из-за того, какViewPager работает. Я'завтра в решение.
 Herry07 мар. 2013 г., 08:30
позвольте мне объяснить, что я сделал. Я использую поддержку Api демо ViewPager, чтобы сделать вкладки с проведением. Теперь на вторых вкладках есть один FrameLayout, который загружает реальный фрагмент, у которого есть список элементов, и теперь, когда я нажимаю на элемент, он заменяет этот FrameLayout новым подробным фрагментом элемента. Все это работает нормально, проблема только в том, что когда я нахожусь на странице сведений и нажмите кнопку назад, чтобы уничтожить активность, а не показывать предыдущий фрагмент, который был списком предметов.
 Herry07 мар. 2013 г., 08:45
@CommonsWare я попробовал ваш код, который показывает одну кнопку сверху, а когда нажмите на нее, нажмите кнопку и текстовое представление под ним. Теперь, когда я нажимаю кнопку возврата Android, это разрушает активность, но я хочу показать предыдущее состояние фрагмента, которое будет только Button no Textview под этим.
 CommonsWare14 нояб. 2012 г., 17:54
@Luksprog: это нет сценарий, о котором я думал. Я'я буду работать над образцом, гдеViewPager Сам размещен фрагментом и имеет фрагменты для своих страниц. Тотдолжен просто пройти мимоgetChildFragmentManager() кPagerAdapter, но я хочу попробовать это в первую очередь. Ваш пример демонстрируетViewPager держать фрагменты, которые сами содержат другие фрагменты - совершенно разумно, только не то, о чем я думал, когда читал вопрос.
 Luksprog14 нояб. 2012 г., 22:21
@ ComomWare Я действительно надеюсь, что использование этого хочет. Тем не менее, я'мы проверили прохождениеgetChildFragmentManager кPagerAdapter набор дляViewPager содержится вFragment и это работает довольно хорошо.
 Herry07 мар. 2013 г., 08:26
@Luksprog: У меня есть проблема, чтобы получить предыдущий фрагмент от дочернего фрагмента на андроид назад нажмите клавишу.
 Luksprog15 нояб. 2012 г., 11:59
@sabadow Посмотрите мой отредактированный ответ и посмотрите, отвечает ли редактирование на некоторые ваши вопросы.

Ваш ответ на вопрос