Как добавить фрагмент внутри 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
чтобы узнать, как работает.
4 ответа
Предполагая, что вы создали правильные макеты 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);
}
}
При создании экземпляра FragmentPagerAdapter важно использовать Fragment.getChildFragmentManager(). Также обратите внимание, что вы не можете использовать Fragment.setRetainInstance() для дочерних фрагментов, иначе вы получите исключение.
Исходный код можно найти по адресу: https://github.com/marcoRS/nested-fragments
Редактировать: если вы хотите заменить все содержимое страницы в 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, и вот что я хотел сделать..
Я реализовал это с помощью предыдущих вопросов и ответов от StackOverFlow, и вот ссылка.
С легкостью используйте компонент навигации в своем приложении! затем в своем слушателе скопируйте этот код:
findNavController().navigate('Your action Id)
- Ваш идентификатор действия, который IDE создала автоматически для вас.