Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shared element when using startActivityForResult

Tags:

I have an app with two activities, where the second functions as an image "picker" and delivers some information to the first, so that an ImageView can be updated accordingly.

For this, I'm calling the second activity through startActivityForResult(), and updating the ImageView according to information received on onActivityResult().

The problem arises when I try to animate a shared element between the picker and the main Activity: it seems like the transition "snapshots" the first Activity, and even if the ImageView is updated as soon as the Activity resumes, the transition animation will "flicker" an older version of the View before showing the current version.

Here's an example app I made to illustrate what I'm talking about:

Visual description of the bug

What would be the best way to implement this animation seamlessly? Should another approach be used?

Here's the code used for the example:

Main Activity

public class MainActivity extends AppCompatActivity {

    ImageView mainImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportActionBar().setTitle("Main Activity");

        mainImageView = (ImageView) findViewById(R.id.imageView);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, PickerActivity.class);
                ActivityOptionsCompat options = ActivityOptionsCompat.
                        makeSceneTransitionAnimation(MainActivity.this, mainImageView, "shape_transition");
                startActivityForResult(intent, 1, options.toBundle());
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        int shapeNumber = intent.getIntExtra("shape_number", -1);

        switch (shapeNumber) {
            case 1:
                mainImageView.setImageResource(R.drawable.blue);
                break;
            case 2:
                mainImageView.setImageResource(R.drawable.green);
                break;
            default:
                //something else
                break;
        }


    }
}

Picker Activity:

public class PickerActivity extends AppCompatActivity {

    ImageView blueImageView;
    ImageView greenImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_picker);
        getSupportActionBar().setTitle("Picker Activity");

        blueImageView = (ImageView) findViewById(R.id.imageView2);

        blueImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                blueImageView.setTransitionName("shape_transition");
                Intent intent = new Intent(PickerActivity.this, MainActivity.class);
                intent.putExtra("shape_number", 1);
                setResult(RESULT_OK, intent);
                finishAfterTransition();
            }
        });

        greenImageView = (ImageView) findViewById(R.id.imageView3);

        greenImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                greenImageView.setTransitionName("shape_transition");
                Intent intent = new Intent(PickerActivity.this, MainActivity.class);
                intent.putExtra("shape_number", 2);
                setResult(RESULT_OK, intent);
                finishAfterTransition();
            }
        });
    }
}

Main Activity xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="demonstration.sharedelementproblemexample.MainActivity">

    <ImageView
        android:layout_width="128dp"
        android:layout_height="128dp"
        android:id="@+id/imageView"
        android:transitionName="shape_transition"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:src="@drawable/red" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Pick"
        android:id="@+id/button"
        android:layout_below="@+id/imageView"
        android:layout_alignParentStart="true" />
</RelativeLayout>

Picker Activity xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="demonstration.sharedelementproblemexample.PickerActivity">

    <ImageView
        android:layout_width="128dp"
        android:layout_height="128dp"
        android:id="@+id/imageView2"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:src="@drawable/blue" />

    <ImageView
        android:layout_width="128dp"
        android:layout_height="128dp"
        android:id="@+id/imageView3"
        android:src="@drawable/green"
        android:layout_alignParentStart="true"
        android:layout_alignTop="@+id/imageView2" />
</RelativeLayout>
like image 602
ememorais Avatar asked Sep 08 '16 04:09

ememorais


1 Answers

While working on another project, I found a way to prevent this flickering from happening.

In the first Activity (the one that sent the request), instead of updating the view that initially transitioned through the onActivityResult(int requestCode, int resultCode, Intent intent) method, you should override onActivityReenter(int resultCode, Intent data) and update the view from there.

This method is called before the transition animation begins, and you still have access to information from the other Activity through the Intent parameter.

Here's the same example app using this solution:

picture showing the fix

And here's the overriden method:

@Override
public void onActivityReenter(int resultCode, Intent data) {
    int shapeNumber = data.getIntExtra("shape_number", -1);

    switch (shapeNumber) {
        case 1:
            mainImageView.setImageResource(R.drawable.blue);
            break;
        case 2:
            mainImageView.setImageResource(R.drawable.green);
            break;
        default:
            //something else
            break;
    }
    super.onActivityReenter(resultCode, data);
}
like image 107
ememorais Avatar answered Sep 24 '22 16:09

ememorais