Su Wang
Su Wang

Reputation: 61

Android Shared Element Animation doesn't work for me

I am following the instruction on https://developer.android.com/training/material/animations.html and trying to implement an animation with shared element between activities, but it doesn't work for me, I searched a lot but could not find an answer, is there anyone who can help to take a look? Thank you so much!

My steps:

1, create a directory "transition" under my "res" directory, and then create a file list_to_details.xml there:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeImageTransform/>
</transitionSet>

2, create a directory "values-v21" under my "res" directory, and then create a file styles.xml there(setting the transition defined above in step 1):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="android:Theme.Material">
        <!-- enable window content transitions -->
        <item name="android:windowContentTransitions">true</item>

        <!-- specify enter and exit transitions -->
        <item name="android:windowSharedElementEnterTransition">@transition/list_to_detail</item>
        <item name="android:windowSharedElementExitTransition">@transition/list_to_detail</item>
    </style>
</resources>

3, set the application theme to "AppTheme" which is defined in the new styles file

<application
        android:name="com.myapp.MyApplication"
        android:allowBackup="false"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

4, Add the transitionName to the shared element in Activity A and B: A: B:

5, Add code to start Activity B in Activity A:

expandedImageView.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
    ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(DetailDemoActivity.this, v, "todetail");
    Intent intent = new Intent(DetailDemoActivity.this, AnotherDetailDemoActivity.class);
    intent.putExtra("original_url", originalUrl);
    ActivityCompat.startActivity(DetailDemoActivity.this, intent, options.toBundle());
  }
});

6, try the app but it doesn't play animation, I am guessing the reason might be that I have an async task in Activity B to load the image, but it still doesn't work after I tried postponeEnterTransition, I also tried getSharedElementEnterTransition, but debugger showed it was a null, see my code:

@Override
protected void onCreate(Bundle savedInstanceState) {
  postponeEnterTransition();

  Intent intent = this.getIntent();
  originalUrl = intent.getStringExtra("original_url");

  GetBigImageAsyncTask  getBigImageTask = new GetBigImageAsyncTask();
  getBigImageTask.execute();

  super.onCreate(savedInstanceState);
  setContentView(R.layout.another_detail_demo);
  // I have also tried setTransitionName() here but it doesn't work too
}

private void scheduleStartPostponedTransition(final View sharedElement) {
  sharedElement.getViewTreeObserver().addOnPreDrawListener(
      new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
          sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
          startPostponedEnterTransition();
          return true;
        }
      });
}

private class GetBigImageAsyncTask extends AsyncTask<Object, Void, Bitmap> {
  @Override
  protected Bitmap doInBackground(Object... urls) {
    InputStream input = null;
    HttpURLConnection connection = null;
    try {
      URL url = new URL(originalUrl);
      connection = (HttpURLConnection) url.openConnection();
      connection.setDoInput(true);
      connection.connect();
      input = connection.getInputStream();
      Bitmap myBitmap = BitmapFactory.decodeStream(input);
      return myBitmap;
    } catch (Exception e) {
      return null;
    } finally {
      if (connection != null) {
        connection.disconnect();
      }

      if (input != null) {
        try {
          input.close();
        } catch (Exception e) {

        }
      }
    }
  }

  @Override
  protected void onPostExecute(Bitmap result) {
    ImageView expandedImageView =
        (ImageView) findViewById(R.id.another_demo_expanded_image);
    expandedImageView.setImageDrawable(new BitmapDrawable(result));
    scheduleStartPostponedTransition(expandedImageView);

    final Transition transition = AnotherDetailDemoActivity.this.getWindow().getSharedElementEnterTransition();

    // In fact here the object transition is null 
    if (transition != null) {
      // There is an entering shared element transition so add a listener to it
      transition.addListener(new Transition.TransitionListener() {
        @Override
        public void onTransitionEnd(Transition transition) {
          transition.removeListener(this);
        }

        @Override
        public void onTransitionStart(Transition transition) {
        }

        @Override
        public void onTransitionCancel(Transition transition) {
          // Make sure we remove ourselves as a listener
          transition.removeListener(this);
        }

        @Override
        public void onTransitionPause(Transition transition) {
          // No-op
        }

        @Override
        public void onTransitionResume(Transition transition) {
          // No-op
        }
      });
    }
  }
}

Is there anything wrong or missed in my steps? Any help is highly appreciated!

Upvotes: 2

Views: 2399

Answers (1)

Su Wang
Su Wang

Reputation: 61

Just made it work.

Two problems that affect:

  1. I need to use java code change instead of the XML changes(not sure why, I guess maybe there's something wrong in my Android SDK to parse the XML changes)
  2. I need to add window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) to make it work, this feature is NOT mentioned in the Android developer site, but someone mentioned it in some stakeoverflow question.

Upvotes: 4

Related Questions