Переход сцены Android

Я хотел бы создать простой переход сцены, используя TransitionManager и среду сцены в Android. Переход отлично работает при переходе от сцены1 к сцене2, но не работает в обратном направлении.

Идея состоит в том, что нажатие на кнопку (scene1) открывает простой макет с несколькими кнопками (scene2), а затем возвращается в исходное состояние после того, как пользователь нажал кнопку внутри scene2.

Scene1 Scene2

Сцена1 -> Сцена2 работает нормально. Все хорошо анимировано (см. изображения выше). Затем я хочу переключить Scene2 -> Scene1 и получить следующую ошибку:

java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
        at android.view.ViewGroup.addViewInner(ViewGroup.java:3880)
        at android.view.ViewGroup.addView(ViewGroup.java:3733)
        at android.view.ViewGroup.addView(ViewGroup.java:3678)
        at android.view.ViewGroup.addView(ViewGroup.java:3654)
        at android.transition.Scene.enter(Scene.java:177)
        at android.transition.TransitionManager.changeScene(TransitionManager.java:199)
        at android.transition.TransitionManager.go(TransitionManager.java:365)
        at com.test.MainActivity$2.onClick(MainActivity.java:84)

Вопрос: как отменить переход от сцены 2 к сцене 1? Что мне здесь не хватает?

Вот код из Activity и layouts:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initToggle();
    }

    private void initToggle() {

        final RelativeLayout sceneBase = (RelativeLayout) findViewById(R.id.toggle);

        final ViewGroup scene2closed = (ViewGroup)getLayoutInflater().inflate(R.layout.closed, sceneBase, true);
        final ViewGroup scene2opened = (ViewGroup)getLayoutInflater().inflate(R.layout.opened, sceneBase, false);

        final Scene sceneOpen = new Scene(sceneBase, scene2opened);
        final Scene sceneClose = new Scene(scene2opened, scene2closed);

        final Transition t = new AutoTransition();
        t.setDuration(100);

        scene2closed.findViewById(R.id.toggle_scene).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TransitionManager.go(sceneOpen, t);
            }
        });

        scene2opened.findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TransitionManager.go(sceneClose, t);
            }
        });
    }
}

activity_main.xml

<RelativeLayout
    android:id="@+id/toggle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_marginBottom="8dip"
    android:layout_marginRight="8dip"
    android:layout_marginLeft="8dip"
    android:background="#ffffff">

</RelativeLayout>

closed.xml

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toggle_scene"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="4dip"
android:padding="5dip"
android:visibility="visible">

    <ImageView
        android:layout_width="30dip"
        android:layout_height="30dip"
        android:scaleType="fitCenter"
        android:background="#444444" />
</RelativeLayout>

open.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="visible"
android:padding="5dip">

<LinearLayout
    android:id="@+id/toggleMapTypes"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minHeight="0dip"
        android:background="#03A9F4"
        android:padding="5dip"
        android:text="button1"
        android:textAllCaps="false"
        android:textColor="#ffffff" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:minHeight="0dip"
        android:padding="5dip"
        android:text="button2"
        android:textAllCaps="false"
        android:textColor="#03A9F4" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:minHeight="0dip"
        android:padding="5dip"
        android:text="button3"
        android:textAllCaps="false"
        android:textColor="#03A9F4" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:minHeight="0dip"
        android:maxLines="1"
        android:padding="5dip"
        android:text="button4"
        android:textAllCaps="false"
        android:textColor="#03A9F4" />

</LinearLayout>


person Devdroid    schedule 29.09.2015    source источник


Ответы (1)


Мне удалось выяснить источник проблемы, на случай, если любой другой наткнется на тот же самый. При надувании сцен внутри кода я сначала назначал их макету с помощью LayoutInflater:

// WRONG 3. parameter is true (add to root layout) 
final ViewGroup scene2closed = (ViewGroup)getLayoutInflater().inflate(R.layout.closed, sceneBase, true);

Решением было не добавлять в корень макет первой сцены, а включить сцену:

// CORRECT 3. param inside .inflate call (do NOT add to root layout) 
final ViewGroup scene2closed = (ViewGroup)mInflater.inflate(R.layout.include_map_select_closed, sceneBase, false);
final Scene sceneClose = new Scene(sceneBase, scene2closed);
sceneClose.enter();

После того, как я инициировал первую сцену с помощью sceneClose.enter(), макет переключается по желанию.

person Devdroid    schedule 30.09.2015