4

In my project I'm using a RecyclerView to display a list of items with thumbnails. When the user clicks on an item a DetailView gets opened, where the image is displayed on the top. I'm trying to share some elements between this fragments, but the transition only works when entering the detail fragment, not when returning from it.

In my ListAdapter I set the TransitionName and inform the ListFragment when the user clicks on an item:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        viewHolder.image.setTag(Constants.SHARED_NAME_IMAGE + item.itemId);
}

click event:

@OnClick(R.id.root)
 public void onClickedItem() {
        List<Pair<View, String>> sharedElements = new ArrayList<>();
        sharedElements.add(new Pair<View, String>(image, (String) image.getTag()));
        interactionListener.onItemSelected(data.get(getAdapterPosition() - headerItemCount).type, data.get(getAdapterPosition() - headerItemCount).itemId, sharedElements);
 }

Then in the ListFragment I'm starting the DetailFragment:

public void navigateToFragment(Fragment curFragment, Fragment nextFragment,
                               boolean addToBackStack, List<Pair<View, String>> sharedElements) {
    if (nextFragment == null) {
        return;
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && sharedElements != null && curFragment != null) {
        // Setup transition on first fragment
        curFragment.setSharedElementEnterTransition(TransitionUtil.getReturnTransition(this));
        curFragment.setSharedElementReturnTransition(TransitionUtil.getEnterTransition(this));
        curFragment.setEnterTransition(null);
        curFragment.setExitTransition(null);

        // Setup transition on second fragment
        nextFragment.setSharedElementEnterTransition(TransitionUtil.getEnterTransition(this));
        nextFragment.setSharedElementReturnTransition(TransitionUtil.getReturnTransition(this));
        nextFragment.setEnterTransition(null);
        nextFragment.setExitTransition(null);

        // Add second fragment by replacing first
        FragmentTransaction ft = getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.container, nextFragment);
        if (addToBackStack) {
            ft.addToBackStack("fragment");
        }

        for (Pair<View, String> sharedElement : sharedElements) {
            ViewCompat.setTransitionName(sharedElement.first, sharedElement.second);
            ft.addSharedElement(sharedElement.first, sharedElement.second);
        }

        // Apply the transaction
        ft.commit();
    } else {
        FragmentTransaction ft = getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.container, nextFragment);
        if (addToBackStack) {
            ft.addToBackStack("fragment");
        }
        ft.commit();
    }
}

Finally I'm setting the current transition name (as it depends on the itemId) in onCreateView() of the DetailFragment:

ViewCompat.setTransitionName(header, Constants.SHARED_NAME_IMAGE + itemId);
Katharina
  • 1,612
  • 15
  • 27

1 Answers1

3

I just solved the issue: there were 2 problems:

  1. I've overwritten my list adapter (and therefore the transition names have been removed)
  2. I haven't set the transition name in onBindViewHolder

To resolve #1 I changed setUpList(){...} like here (the first if is important!):

 private void setupList() {
    if (adapter != null) {
        list.setAdapter(adapter);
        linearLayoutManager = new LinearLayoutManager(getActivity());
        list.setLayoutManager(linearLayoutManager);
        setScrollListener();
        return;
    }

    refreshLayout.setColorSchemeColors(ResourcesCompat.getColor(getResources(), R.color.main_color_2, getActivity().getTheme()));
    refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            loadList(true);
        }
    });

    adapter = new ListAdapter((int) (DisplayUtils.getWidth(getActivity()) * 0.6), this);
    list.setAdapter(adapter);

    linearLayoutManager = new LinearLayoutManager(getActivity());
    list.setLayoutManager(linearLayoutManager);

    refreshLayout.post(new Runnable() {
        @Override
        public void run() {
            refreshLayout.setRefreshing(true);
            loadFilterItems();

To resolve #2 I just replaced setTag(..) with setTransitionName(..)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                vh.image.setTransitionName(Constants.SHARED_NAME_IMAGE + item.itemId);
            }

and in my onClick method:

 List<Pair<View, String>> sharedElements = new ArrayList<>();
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            sharedElements.add(new Pair<View, String>(image, image.getTransitionName()));
        }
 interactionListener.onItemSelected(data.get(getAdapterPosition() - headerItemCount).type, data.get(getAdapterPosition() - headerItemCount).itemId, sharedElements);
Katharina
  • 1,612
  • 15
  • 27