Devdroid
Devdroid

Reputation: 941

Scene transition Android

I would like to create a simple scene transition using the TransitionManager and Scene framework in Android. The transition works fine when transitioning from scene1 to scene2, but does not work in the opposite direction.

The idea is that a click on the button (scene1) opens a simple layout with several buttons (scene2) and then returns to its initial state after the user pressed a button inside scene2.

Scene1 Scene2

Scene1 -> Scene2 works fine. Everything is well animated (see images above). Then I want to switch Scene2 -> Scene1 and get the following error:

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)

Question: How can I reverse the transition from Scene2 -> Scene1? What am I missing here?

Here is the code from the Activity and 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>

Upvotes: 0

Views: 2195

Answers (1)

Devdroid
Devdroid

Reputation: 941

I managed to figure out the source of the problem, in case any other stumbles upon the same one. When inflating the scenes inside the code, I firstly assigned it to the layout using the LayoutInflater:

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

The solution was not to add the first scene layout to the root, but to enable the scene:

// 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();

After I initiated the first scene using sceneClose.enter(), the layout toggles as desired.

Upvotes: 1

Related Questions