Программно добавить фрагмент во внутреннюю ViewGroup

Я пытаюсь добавить два фрагмента в следующий макет:

dialog_empty_linear_layout.xml:

    <LinearLayout
        android:id="@+id/ParentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:orientation="vertical" >
    </LinearLayout>

</RelativeLayout>

Используя следующий код:

setContentView(R.layout.dialog_empty_linear_layout);

int parentViewId = getIntent().getIntExtra(PARENT_VIEW_ID, -1); // == R.id.ParentLayout
if (parentViewId == -1)
    parentViewId = android.R.id.content;

/*
 * Extracting Fragments types
 */
Class<? extends Fragment>[] fragmentTypes = getFragments(); // there are two fragments here!

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
for (Class<? extends Fragment> fragmentType  : fragmentTypes) {
    Fragment fragment = Tools.createNewInstance(fragmentType);
    ft.add(parentViewId, fragment);
}
ft.commitAllowingStateLoss();

При выполнении кода я получаю следующую ошибку:

Причина: java.lang.IllegalStateException: указанный дочерний элемент уже имеет родителя. Вы должны сначала вызвать removeView() для родителя дочернего элемента.

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

Итак, я проследил трассировку стека и проверил, о каком дочернем и о каком родителе идет речь, поскольку исключение не дало никакой дополнительной информации об этом...

Я был больше удивлен, узнав, что Child - это LinearLayout (например, R.ParentLayout), а Parent - это RelativeLayout, обертывающий его.

Возможно, я снова упускаю очевидное, но я подумал, что:

ft.add(parentViewId, fragment);

Предположим, что нужно добавить фрагмент в макет parentViewId, а не пытаться добавить макет parentViewId в его родительский макет...

ТАКЖЕ, если я использую следующий XML, все работает нормально:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ParentLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

</LinearLayout>

Есть идеи?


comment
Это выстрел в темноте, но если вы создаете свои фрагменты с помощью инфлятора (getActivity().getLayoutInflater().inflate(XmlPullParser parser, ViewGroup root)) и не устанавливаете для второго параметра значение null, тогда фрагмент будет присоединен к этой ViewGroup в качестве своего родителя, поэтому, когда вы ссылаетесь на него в своем code он уже будет прикреплен к чему-то другому.   -  person nstosic    schedule 27.10.2013
comment
И как фрагмент будет прикреплен к действию без создания нового макета для фрагмента и прикрепления его к представлению?   -  person TacB0sS    schedule 27.10.2013


Ответы (1)


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

Переопределение этого метода во фрагменте:

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

А вот и глупость...

У inflater.inflate есть еще одна перегрузка:

    return inflater.inflate(R.layout.fragment_id, container, **addToRoot**);

По какой-то причине я ожидал, что макет фрагмента будет добавлен в контейнер (не доверяйте интуиции), а не добавление контейнера в rootView. До сегодняшнего дня я добавлял все свои фрагменты в свое корневое представление (container == rootView), поэтому этой проблемы не возникало, но как только контейнер не является корневым представлением, я ДОЛЖЕН явно указать addToRoot=false, например.

    return inflater.inflate(R.layout.fragment_id, container, false);

Ну это ребята... глупость булевская!

person TacB0sS    schedule 27.10.2013