7

I implemented the shared element transition between from an image in a RecyclerView to an image in a new Fragment. The RecyclerView is hosted in a fragment hosted by an Activity and the target fragment is hosted inside another Activity.

When I click on my image, the transition is happening like expected and I get to my fragment. But when I click the back button, the transition is trying to put my image at the first position of my RecyclerView while it's currently displaying the image which is not necessarily the first one.

From this situation, I thought since it's a list of image in which I set a transition name inside the XML, maybe when going back, since all image has the same transition name, the process is confused and just get the first image with the given name. So maybe I should dynamically give a different transition name to each of them. I also set the same name to the target image and reset it every time a new image is selected. But it's still not working. Can anyone help me with that?

Here is the code inside my onItemClickListener:

mAdapter.setOnItemClickListener(new RssItemAdapter.OnItemCLickListener(){
    @Override
    public void onItemClick(View view, int position) {
        final RssItem item = mAdapter.getItem(position);
        final RssElementIntent intent = new RssElementIntent(getActivity(), item, position);
        // mRootView is the view of the fragment
        final ImageView image = (ImageView) 
mRootView.findViewById(R.id.rss_element_image);
        image.setTransitionName(getString(R.string.transition_name_rss_feed_picture) + position);
        ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
                        getActivity(), image, RssElementFragment.EXTRA_IMAGE);
        ActivityCompat.startActivity(getActivity(), intent, options.toBundle());
    }
});

Here is the code in the target fragment:

rssImage.setTransitionName(getString(R.string.transition_name_rss_feed_picture) + getArguments().getInt(ARG_ELEMENT_POSITION));
ViewCompat.setTransitionName(rssImage, EXTRA_IMAGE);

And here is the themes.xml :

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/theme_primary</item>
        <item name="colorPrimaryDark">@color/theme_primary_dark</item>
        <item name="android:colorAccent">@color/theme_accent</item>

        <!-- enable window content transitions -->
        <item name="android:windowContentTransitions">true</item>

        <item name="android:windowAllowEnterTransitionOverlap">true</item>
        <item name="android:windowAllowReturnTransitionOverlap">true</item>

        <!-- specify shared element transitions -->
        <item name="android:windowSharedElementEnterTransition">
            @transition/change_image_transform
        </item>
        <item name="android:windowSharedElementExitTransition">
            @transition/change_image_transform
        </item>

    </style>

Edit:

I found my error, I was getting the ImageView from the fragment rootView which was giving me a random ImageView from my RecyclerView, which mean the wrong transition name. So I used the view given by onItemClick and it worked! I also move the setTransitionName() inside the adapter.

mAdapter.setOnItemClickListener(new RssItemAdapter.OnItemCLickListener(){
        @Override
        public void onItemClick(View view, int position) {
            final RssItem item = mAdapter.getItem(position);
            final RssElementIntent intent = new RssElementIntent(getActivity(), item, position);
            // WRONG !
            // final ImageView image = (ImageView) mRootView.findViewById(R.id.rss_element_image);
            // Correct
            final ImageView image = (ImageView) view.findViewById(R.id.rss_element_image);

            ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
                            getActivity(), image, RssElementFragment.EXTRA_IMAGE);
            ActivityCompat.startActivity(getActivity(), intent, options.toBundle());
        }
    });
lcw_gg
  • 679
  • 5
  • 14
  • I think appending `position` to transition name may be troublesome, it works fine without `position` in my case. Maybe you should try to remove `position` in the transition name. – hidro Feb 05 '15 at 09:04
  • I tried and i still get the same result... – lcw_gg Feb 05 '15 at 09:10
  • 2
    In your Adapter for the RecyclerView, in onBindViewHolder, set a unique transitionName per row for each possible shared element. Normally, this comes from a unique row ID of some sort, but if you don't have anything like that, you can use the position as long as you don't have reordering. When going "back" the View is searched by transitionName. If you don't have a way to uniquely identify at binding time, you can override onMapSharedElements to give the framework the hints it needs. – George Mount Feb 06 '15 at 01:11
  • You might find this sample implementation helpful (as an example): https://github.com/alexjlockwood/activity-transitions – Alex Lockwood Feb 06 '15 at 02:51
  • 1
    George Mount, what you told me led me to the solution! I set a unique name to each image in my adapter and while debugging I realized that the `ImageView` I was passing to the `ActivityOptionsCompat` did not have the same transition name as the ImageView I was clicking. I was getting this `ImageView` from the rootView and somehow, it was returning a random `ImageView` from the `RecyclerView`. So instead of getting it from the rootView, I used the view that `onItemClick()` give and it worked :) – lcw_gg Feb 06 '15 at 02:52
  • @lcw_gg If you found a solution, you should post it as an answer and mark it as accepted so that it is clear that the question has been resolved. :) – Alex Lockwood Feb 06 '15 at 03:24
  • I posted the answer but I can accept it only tomorrow... – lcw_gg Feb 06 '15 at 04:13

1 Answers1

10

I found my error, I was getting the ImageView from the fragment rootView which was giving me a random ImageView from my RecyclerView, which mean the wrong transition name. So I used the view given by onItemClick and it worked! I also move the setTransitionName() inside the adapter.

mAdapter.setOnItemClickListener(new RssItemAdapter.OnItemCLickListener(){
        @Override
        public void onItemClick(View view, int position) {
            final RssItem item = mAdapter.getItem(position);
            final RssElementIntent intent = new RssElementIntent(getActivity(), item, position);
            // WRONG !
            // final ImageView image = (ImageView) mRootView.findViewById(R.id.rss_element_image);
            // Correct
            final ImageView image = (ImageView) view.findViewById(R.id.rss_element_image);

            ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
                            getActivity(), image, RssElementFragment.EXTRA_IMAGE);
            ActivityCompat.startActivity(getActivity(), intent, options.toBundle());
        }
    });
lcw_gg
  • 679
  • 5
  • 14