10

I have 2 fragments: fragment 1 containing recyclerview & fragment 2 having detail view for selected item. There is a shared element imageview between these 2 fragments. While transitioning from fragment 1 to 2 I want to see standard shared element transition effect, but it doesn't seem to work with recyclerview. Because if I use just another separate view in 1st fragment instead of recyclerview, it exhibits proper transition. Note that I have assigned position based unique transition names to recyclerview item images.

Code is as follows: MyActivity.java

public class MyActivity extends Activity {

private static final String TAG = MyActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    if (savedInstanceState == null) {
        getFragmentManager().beginTransaction()
                .add(R.id.main_container, new PlaceholderFragment())
                .commit();
    }
}

public static class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder> {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);
    }

    private OnItemClickListener mItemClickListener;

    List<Integer> items = new ArrayList<Integer>();
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mItemClickListener = listener;
    }


    public ImageAdapter() {
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
        items.add(1);
    }

    @Override
    public ImageAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, null);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int i) {
        viewHolder.container.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                if (mItemClickListener != null) {
                    mItemClickListener.onItemClick(view, i);
                }
            }
        });
        viewHolder.imgDummy.setTransitionName("test" + i);
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public View container;
        public View imgDummy;

        public ViewHolder(View itemView) {
            super(itemView);
            container = itemView.findViewById(R.id.container);
            imgDummy = itemView.findViewById(R.id.imgDummy);
        }
    }
}
/**
 * A placeholder fragment containing a simple view.
 */
@SuppressLint("ValidFragment")
public class PlaceholderFragment extends Fragment {

    private RelativeLayout.LayoutParams lp;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_my, container, false);
        final View imgDummy2 = rootView.findViewById(R.id.imgDummy2);
        imgDummy2.setTransitionName("test");

        RecyclerView list = (RecyclerView) rootView.findViewById(R.id.streams_list);
        list.setLayoutManager(new LinearLayoutManager(getActivity()));
        ImageAdapter adapter = new ImageAdapter();
        adapter.setOnItemClickListener(new ImageAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {                  
                View imgDummy = view.findViewById(R.id.imgDummy);

                SecondFragment secondFragment = new SecondFragment();
                secondFragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.trans_move));

                secondFragment.setId(imgDummy.getTransitionName());
                android.app.FragmentTransaction trans = getFragmentManager().beginTransaction();
                trans.replace(R.id.main_container, secondFragment);
                trans.addToBackStack(null);
                trans.addSharedElement(imgDummy, imgDummy.getTransitionName());
                trans.commit();
            }
        });
        list.setAdapter(adapter);

        return rootView;
    }
}

public static class SecondFragment extends Fragment {
    private String mId;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.second_fragment, container, false);
        rootView.findViewById(R.id.imgDummy).setTransitionName(mId);
        return rootView;
    }

    public void setId(String id) {
        mId = id;
    }
}
}

If I change following 2 lines:

secondFragment.setId(imgDummy.getTransitionName());
trans.addSharedElement(imgDummy, imgDummy.getTransitionName());

by

secondFragment.setId(imgDummy2.getTransitionName());
trans.addSharedElement(imgDummy2, imgDummy2.getTransitionName());

then I can see imgDummy2 image transitioning properly, probably since it's outside of recyclerview.

Any idea how can I apply same within recyclerview as well?

Ankur
  • 602
  • 8
  • 24
  • Have you read this http://www.androiddesignpatterns.com/2015/01/activity-fragment-shared-element-transitions-in-depth-part3a.html ? – pskink Jan 17 '15 at 14:28
  • 2
    @pskink Yes, I have spent almost entire day searching for exact solution, but found no working solution exactly matching with my requirement. Link you have posted is good in general for understanding the transition basics, but it has nothing specific to recyclerview where it's not working. – Ankur Jan 17 '15 at 14:46
  • try this if its what you need: http://pastebin.com/yEh2urqp – pskink Jan 17 '15 at 20:10
  • @pskink Major change I can see is just the transition passed to setSharedElementEnterTransition() which is now AutoTransition. With this as well behavior is same where transition effect starts from top of recycler view rather than actual position of recyclerview child item. – Ankur Jan 17 '15 at 20:29
  • No the blue rectangle starts enlarging from the item you clicked in RV – pskink Jan 17 '15 at 20:32
  • @pskink On my Nexus 5 it's not working that way. I have uploaded my code here: [link]http://wikisend.com/download/120672/brockoli-fragmentsharedelements-87421a65f2aa.zip[link]. If possible, see if same code works at your side properly. – Ankur Jan 17 '15 at 20:46
  • I'm mobile so dont wanna download 2.5 Mb of sources, my code had 80 lines of code so make your short too, btw did you try to run it on official v5 avd emulator? – pskink Jan 17 '15 at 20:51
  • @pskink No problem. Yesterday, I had just included major change from your code which I could figure out was AutoTransition, into mine code. If I run your given code entirely as it is, it runs ok for transition from rootfragment to itemfragment but not in the reverse case. After this I just spent some time to find out why your code is working even for the transition from rootfragment to itemfragment. It's because you have just the simple TextView as RecyclerView item. Keeping it inside RelativeLayout results in no transition effect. – Ankur Jan 18 '15 at 17:02
  • you are wrong: see http://pastebin.com/DCBmqzgh – pskink Jan 18 '15 at 17:24
  • @pskink Here you have used different shared element in 1st & 2nd fragment. I thought both the fragments must have same shared element (in our case TextView) & hence I tried setting transition name on child textview instead of its parent & added this textview as shared element, but you have added directly recyclerview item's parent view as shared element, although in the itemfragment it's just the simple TextView. But still on back press, reverse transition animation is an issue, right? – Ankur Jan 18 '15 at 19:04
  • This is because Fragment Transitions are evil, fragments are evil too... better use Activities, not fragments – pskink Jan 18 '15 at 19:12
  • You can find your answer here: http://stackoverflow.com/questions/38157910/how-to-use-shared-element-transition-between-firstfragment-including-recyclervi – Alireza Noorali Jul 04 '16 at 10:04
  • @AlirezaNoorali this question is not about transition between activities. It's about fragments. So your link becomes invalid for this question. – Ankur Jul 07 '16 at 14:18

1 Answers1

1

I know its way late. But was struggling with this and finally got transition animation from recycler view in fragment A to fragment B working.

try changing imgDummy.getTransitionName()) in the below line

    trans.addSharedElement(imgDummy, imgDummy.getTransitionName());

to the transition name of the ImageView in fragmentB

Ragesh Ramesh
  • 3,470
  • 2
  • 14
  • 20