Search code examples
androidandroid-5.0-lollipop

Transition of nested shared elements does not starts from the expected place


TL;DR Why this transition does not start from the expected place?

That is, the place where is the CardView.

enter image description here

Platform/Deps: Android Studio 1.0-RC2, TargetSdk 21, MinSdk 21, AppCompat-21.0.2, CardView-21.0.2, RecyclerView-21.0.2.

Tested On: Genymotion Nexus 5 Lollipop Preview

The Code (Simplified)

I have three shared elements:

Source:

<CardView
    android:transitionName="cardView">
    <ImageView
      android:transitionName="imageView">
    <TextView
      android:transitionName="textView">

Target:

<RelativeLayout
    android:transitionName="cardView">
    <ImageView
      android:transitionName="imageView">
    <TextView
      android:transitionName="textView">

Note below that the transition names are added programmatically. This is because CardView are holded on a RecyclerView and there are many copies of it. I've tried using the same name (as in the XML instance) but doesn't work neither.

The ReciclerView.Adapter does this:

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
    //...
    ViewCompat.setTransitionName(viewHolder.mCardView, "cardViewTransition" + position);
    ViewCompat.setTransitionName(viewHolder.mImageView, "imageTransition" + position);
    ViewCompat.setTransitionName(viewHolder.mTextView, "textTransition" + position);
    //...
}

The HomeActivity does this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);
    getWindow().requestFeature(android.view.Window.FEATURE_ACTIVITY_TRANSITIONS);
    // ..
    mRecyclerView.addOnItemTouchListener(
        new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() {
            @Override public void onItemClick(View view, int position) {
                Intent intent = new Intent(selfContext, DetailActivity.class);

                View imageView = view.findViewById(R.id.imageView);
                TextView textView = (TextView)view.findViewById(R.id.textView);

                Bundle extras = new Bundle();
                extras.putInt("position", position);
                extras.putString("text", textView.getText().toString());
                intent.putExtras(extras);
                String name = ViewCompat.getTransitionName(view);
                ActivityOptionsCompat options =
                    ActivityOptionsCompat.makeSceneTransitionAnimation(selfContext
                            ,Pair.create(view, ViewCompat.getTransitionName(view))
                            ,Pair.create(imageView, ViewCompat.getTransitionName(imageView))
                            ,Pair.create((View)textView, ViewCompat.getTransitionName(textView))
                    );
                ActivityCompat.startActivity(selfContext, intent, options.toBundle());
            }
        })
    );
    ///...
}

The DetailActivity does this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);
    getWindow().requestFeature(android.view.Window.FEATURE_ACTIVITY_TRANSITIONS);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail);

    // ...

    Bundle extras = getIntent().getExtras();
    int mPositionRef = extras.getInt("position");
    View base = findViewById(R.id.detail_layout);
    View image = findViewById(R.id.imageView);
    TextView text = (TextView) findViewById(R.id.txtLabel);
    text.setText(extras.getString("text"));

    ViewCompat.setTransitionName(base, "cardViewTransition" + mPositionRef);
    ViewCompat.setTransitionName(image, "imageTransition" + mPositionRef);
    ViewCompat.setTransitionName(text, "textTransition" + mPositionRef);

}

I've debugged and shared elements have the same names in the source and destination.

The Question (Again)

Why this transition does not start from the expected place? That is, the place where is the CardView.

Complete sample in GitHub


Solution

  • There is a known bug in Lollipop related to nested shared elements (i.e. adding both a view group and one of its children as shared elements at the same time), so it might be related to that (source: Glitch when animating nested views in a shared element Activity transition?).

    Try only adding the ImageView and TextView as shared elements instead (not the parent relative layout container).