Фрагмент Внутри Фрагмента
мне нужна помощь относительно работы на фрагмент внутри фрагмента, на самом деле я
я столкнулся с проблемой при нажатии кнопки Назад. Главный экран приложения
имеет кнопки и нажатие на каждой кнопке вид заменить на новый
фрагмент(и этот фрагмент содержится внутри другого фрагмента),
динамическое добавление / замена фрагмента работает нормально, нажав
фрагмент button1 заменен, то же самое происходит при нажатии кнопки, но если
Я снова нажимаю кнопку, получаю исключение:
"Duplicate id 0x7f05000a, tag null, or parent id 0x7f050009 with
another fragment for com........ fragmentname"
означает фрагмент или внутренние фрагменты уже добавлены, и я пытаюсь
чтобы добавить их снова, у кого-нибудь есть идея, как работать с фрагментом внутри
фрагмент и перемещение вперед и назад без каких-либо проблем, Спасибо за
поддержка.
MainActivity, где фрагменты динамические добавлены и
заместить.
public class FragmentInsideFragmentTestActivity extends Activity {
private Button button1;
private Button button2;
private Button button3;
private Button button4;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button1 =(Button) this.findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
button2 =(Button) this.findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
button3 =(Button) this.findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
button4 =(Button) this.findViewById(R.id.button4);
button4.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
onButtonClick(view);
}
});
}
public void onButtonClick(View v) {
Fragment fg;
switch (v.getId()) {
case R.id.button1:
fg=FirstFragment.newInstance();
replaceFragment(fg);
break;
case R.id.button2:
fg=SecondFragment.newInstance();
replaceFragment(fg);
break;
case R.id.button3:
fg=FirstFragment.newInstance();
replaceFragment(fg);
break;
case R.id.button4:
fg=SecondFragment.newInstance();
replaceFragment(fg);
break;
}
}
private void replaceFragment(Fragment newFragment) {
FragmentTransaction trasection =
getFragmentManager().beginTransaction();
if(!newFragment.isAdded()){
try{
//FragmentTransaction trasection =
getFragmentManager().beginTransaction();
trasection.replace(R.id.linearLayout2, newFragment);
trasection.addToBackStack(null);
trasection.commit();
}catch (Exception e) {
// TODO: handle exception
//AppConstants.printLog(e.getMessage());
}
}else
trasection.show(newFragment);
}
}
вот макет: main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
<LinearLayout android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:layout_width="wrap_content"
android:id="@+id/button1"
android:layout_height="wrap_content"
android:text="Button1"></Button>
<Button android:text="Button2"
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<Button android:text="Button3"
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<Button android:text="Button4"
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
</LinearLayout>
<LinearLayout android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"></LinearLayout>
</LinearLayout>
надеюсь, я попытался очистить мою проблему.
13 ответов:
AFAIK, фрагменты не могут содержать другие фрагменты.
обновление
с текущими версиями пакета поддержки Android - или собственные фрагменты на уровне API 17 и выше - вы можете вложить фрагменты, с помощью
getChildFragmentManager(). Обратите внимание, что это означает, что вам нужно использовать версию пакета поддержки Android фрагментов на уровнях API 11-16, потому что, хотя на этих устройствах есть собственная версия фрагментов, эта версия не имеетgetChildFragmentManager().
Так как Android 4.2 (API 17) вложенные фрагменты становятся доступными http://developer.android.com/about/versions/android-4.2.html#NestedFragments
для размещения фрагмента внутри другого фрагмента используйте getChildFragmentManager ()
Он также доступен в библиотеке поддержки!
мне нужно больше контекста, поэтому я сделал пример, чтобы показать, как это делается. Самое полезное, что я прочитал во время подготовки было это:
активность
activity_main.xml
добавить
FrameLayoutв вашей деятельности, чтобы держать родителей фрагмент.<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Activity"/> <FrameLayout android:id="@+id/parent_fragment_container" android:layout_width="match_parent" android:layout_height="200dp"/> </LinearLayout>MainActivity.java
загрузите Родительский фрагмент и реализуйте прослушиватели фрагментов. (См.фрагмент коммуникации.)
import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; public class MainActivity extends AppCompatActivity implements ParentFragment.OnFragmentInteractionListener, ChildFragment.OnFragmentInteractionListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Begin the transaction FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.parent_fragment_container, new ParentFragment()); ft.commit(); } @Override public void messageFromParentFragment(Uri uri) { Log.i("TAG", "received communication from parent fragment"); } @Override public void messageFromChildFragment(Uri uri) { Log.i("TAG", "received communication from child fragment"); } }Родительский Фрагмент
fragment_parent.xml
добавить
FrameLayoutконтейнер для ребенка фрагмент.<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp" android:background="#91d0c2"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Parent fragment"/> <FrameLayout android:id="@+id/child_fragment_container" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> </LinearLayout>ParentFragment.java
использовать
getChildFragmentManagerнаonViewCreatedдля настройки дочернего фрагмента.import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; public class ParentFragment extends Fragment { private OnFragmentInteractionListener mListener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_parent, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { Fragment childFragment = new ChildFragment(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.replace(R.id.child_fragment_container, childFragment).commit(); } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } public interface OnFragmentInteractionListener { // TODO: Update argument type and name void messageFromParentFragment(Uri uri); } }Фрагмент Ребенка
fragment_child.xml
здесь нет ничего особенного.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp" android:background="#f1ff91"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Child fragment"/> </LinearLayout>ChildFragment.java
здесь нет ничего особенного, любой.
import android.support.v4.app.Fragment; public class ChildFragment extends Fragment { private OnFragmentInteractionListener mListener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_child, container, false); } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } public interface OnFragmentInteractionListener { // TODO: Update argument type and name void messageFromChildFragment(Uri uri); } }Примечания
- библиотека поддержки используется так, что вложенные фрагменты может использоваться до Android 4.2.
фрагменты могут быть добавлены внутри других фрагментов, но тогда вам нужно будет удалить его из родительского фрагмента каждый раз, когда вызывается метод onDestroyView() родительского фрагмента. И снова добавьте его в метод Oncreateview() родительского фрагмента.
просто сделайте так:
@Override public void onDestroyView() { FragmentManager mFragmentMgr= getFragmentManager(); FragmentTransaction mTransaction = mFragmentMgr.beginTransaction(); Fragment childFragment =mFragmentMgr.findFragmentByTag("qa_fragment") mTransaction.remove(childFragment); mTransaction.commit(); super.onDestroyView(); }
Я решил эту проблему. Вы можете использовать библиотеку поддержки и
ViewPager. Если вам не нужно пролистывание жестом, вы можете отключить пролистывание. Так вот какой код для улучшения моего решения:public class TestFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.frag, container, false); final ArrayList<Fragment> list = new ArrayList<Fragment>(); list.add(new TrFrag()); list.add(new TrFrag()); list.add(new TrFrag()); ViewPager pager = (ViewPager) v.findViewById(R.id.pager); pager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) { @Override public Fragment getItem(int i) { return list.get(i); } @Override public int getCount() { return list.size(); } }); return v; } }P. S. Это уродливый код для тестирования, но он улучшает, что это возможно.
П. П. С. внутри фрагмент
ChildFragmentManagerдолжно быть передано вViewPagerAdapter
можно использовать .
пример:
родитель фрагмент :
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { rootView = inflater.inflate(R.layout.parent_fragment, container, false); } //child fragment FragmentManager childFragMan = getChildFragmentManager(); FragmentTransaction childFragTrans = childFragMan.beginTransaction(); ChildFragment fragB = new ChildFragment (); childFragTrans.add(R.id.FRAGMENT_PLACEHOLDER, fragB); childFragTrans.addToBackStack("B"); childFragTrans.commit(); return rootView; }макет родитель (
parent_fragment.xml):<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white"> <FrameLayout android:id="@+id/FRAGMENT_PLACEHOLDER" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>Ребенок Фрагмент:
public class ChildFragment extends Fragment implements View.OnClickListener{ View v ; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // TODO Auto-generated method stub View rootView = inflater.inflate(R.layout.child_fragment, container, false); v = rootView; return rootView; } @Override public void onClick(View view) { } }
вы можете добавить
FrameLayoutк фрагменту и замените его другим фрагментом, Когда он инициализируется.таким образом, вы можете считать, что другой фрагмент находится внутри первого фрагмента.
используйте getChildFragmentManager (), перейдите по ссылке : Вложенные Фрагмент
нет поддержки MapFragment, команда Android говорит, что работает над ним с Android 3.0. Здесь более подробная информация о проблеме http://code.google.com/p/android/issues/detail?id=15347&utm_source=buffer&buffer_share=acc72 но что вы можете сделать, создав фрагмент, который возвращает MapActivity. Вот пример кода. Спасибо иназаруку:https://github.com/inazaruk/examples/tree/master/MapFragmentExample
Как это работает:
-MainFragmentActivity-это действие, которое расширяет FragmentActivity и содержит два MapFragments. - MyMapActivity расширяет MapActivity и имеет MapView. - LocalActivityManagerFragment хосты LocalActivityManager. -MyMapFragment расширяет LocalActivityManagerFragment и с помощью TabHost создает внутренний экземпляр MyMapActivity. если у вас есть какие-либо сомнения, пожалуйста, дайте мне знать
В настоящее время во вложенном фрагменте вложенные единицы поддерживаются только в том случае, если они генерируются программно! Таким образом, в настоящее время в схеме компоновки xml не поддерживается вложенный фрагмент макета!
ничего сложного. Мы не можем использовать getFragmentManager() здесь. Для использования фрагментов внутри фрагмента мы используем getChildFragmentManager (). Отдых будет таким же.
Привет я решил эту проблему, поместив каждый фрагмент в отдельный макет.И я сделал только что связанный макет видимым и сделал другие видимости исчезли.
Я имею в виду:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="wrap_content" android:id="@+id/button1" android:layout_height="wrap_content" android:text="Button1"></Button> <Button android:text="Button2" android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="Button3" android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="Button4" android:id="@+id/button4" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout> <LinearLayout android:layout_width="full_screen" android:layout_height="0dp" android:layout_weight="1" android:id="action_For_Button1" android:visibility="visible"> <Fragment android:layout_width="full_screen" android:layout_height="full_screen" android:id="fragment1" . . . / > </LinearLayout> <LinearLayout android:layout_width="full_screen" android:layout_height="0dp" android:id="action_For_Button1" android:layout_weight="1" android:visibility="gone"> <Fragment android:layout_width="full_screen" android:layout_height="full_screen" android:id="fragment2" . . . / > </LinearLayout> . . . </LinearLayout>Я предположил, что вы откроете свою страницу, как кнопка 1 нажата.Вы можете контролировать видимость вашего фрагмента на действие щелчка.Вы можете сделать связанный макет видимым, а другие ушли, и с помощью Диспетчера фрагментов вы можете взять свой фрагмент.Этот подход сработал для меня.И так вид, который имеет видимость: ушел невидим, и он не занимает места для целей макета я думаю, что этот подход не вызывает никаких проблем с пространством.
P. S: Я просто попытался объяснить, что мой код решения может иметь синтаксические ошибки или незавершенную структуру.
что может помочь тем, кто работает на Котлин вы можете использовать функцию расширения Итак, создайте файл kotlin, скажем " util.КТ" и добавить этот кусок кода
fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) { val transaction = childFragmentManager.beginTransaction() transaction.replace(frameId, fragment).commit() }допустим, это класс ребенок
class InputFieldPresentation: Fragment() { var views: View? = null override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { views = inflater!!.inflate(R.layout.input_field_frag, container, false) return views } override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) ... } ... }теперь вы можете добавить детей в отец фрагмент такой
FatherPresentation:Fragment() { ... override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val fieldFragment= InputFieldPresentation() addChildFragment(fieldFragment,R.id.fragmet_field) } ... }где R. id. fragmet_field - это идентификатор макета, который будет содержать фрагмент.Этот Лют находится внутри фрагмента отца, конечно. Вот пример
father_fragment.xml:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" > ... <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:id="@+id/fragmet_field" android:orientation="vertical" > </LinearLayout> ... </LinearLayout>

Comments