0

Hi i have made an app where i'm using shared element transition for some animation between recyclerview which is in fragment and a slider viewpager which is in activity. Now the problem is that when i apply shared element transition and click recyclerview it blinks for a moment and the detail activity starts but without animation and when i press back button shared element animation occurs but that too very glitchy. By glitchy i mean when i press back cardview's white background pops and then image comes over it. For that i saw some tutorials on youtube as well as searched on google and found some related So question but still not able to figure out where i am going wrong with this because i have given same transition name to both the imageviews. so please if someone can assist me here. Thank you

Here is my code for recyclerview and styles.xml

styles.xml

<resources xmlns:tools="http://schemas.android.com/tools">

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowContentTransitions" tools:targetApi="lollipop">true</item>
        <item name="android:windowAllowEnterTransitionOverlap" tools:targetApi="lollipop">true</item>
        <item name="android:windowAllowReturnTransitionOverlap" tools:targetApi="lollipop">true</item>
        <item name="android:windowSharedElementEnterTransition" tools:targetApi="lollipop">@android:transition/move</item>
        <item name="android:windowSharedElementExitTransition" tools:targetApi="lollipop">@android:transition/move</item>
    </style>

</resources>

ViewHolder

 public class VH extends RecyclerView.ViewHolder implements View.OnClickListener{
        ImageView iv;
        TextView tv;
        HWRatioContainer ivc;
        Context context;
        int[] images;

        private AtomicBoolean enterTransitionStarted;
        public static final String EXTRA_TRANSITION_IMAGE = "image";

        CustomButton top_recycler_button;
        public VH(View itemView,Context context,int[] images) {
            super(itemView);
            iv = (ImageView) itemView.findViewById(R.id.iv);
            this.context = context;
            this.images = images;

            this.enterTransitionStarted = new AtomicBoolean();
            top_recycler_button = (CustomButton)itemView.findViewById(R.id.top_recycler_button);
            itemView.setOnClickListener(this);
            //tv = (TextView) itemView.findViewById(R.id.tv);
            ///ivc = (HWRatioContainer) itemView.findViewById(R.id.ivc);
           /*ivc.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        ivc.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    } else {
                        ivc.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    }
                    ivc.setTranslationX(ivc.getWidth() >> 4);
                }
            });*/

        }

        @SuppressLint("RestrictedApi")
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(context,DetailsActivity.class);
            intent.putExtra("slider_image",images[getAdapterPosition()]);
            iv.setTransitionName(context.getString(R.string.first_page_transition));
            ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation((MainActivity)context,iv,ViewCompat.getTransitionName(iv));
            context.startActivity(intent,compat.toBundle());
        }
    }

and code for adapter of viewpager which is in activity

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = layoutInflater.inflate(R.layout.custom_dots_layout,null);
        imageView = (ImageView)view.findViewById(R.id.detail_viewpager_image);
        //Intent intent  = new Intent();
        imageView.setImageResource(getImage());

        if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){
            imageView.setTransitionName(context.getString(R.string.first_page_transition));

        }
        ViewPager viewPager1 = (ViewPager)container;
        viewPager1.addView(view,0);
        return view;
    }
Suleyman
  • 2,765
  • 2
  • 18
  • 31
cooldev
  • 57
  • 9
  • If the enter transition doesn't work, it means that the views are not ready when the animation occurs, so you need to postpone the transition probably, also I would suggest to `setTransitionName` in `onBindViewholder` and not in `onClick`. The second cause may be the transition name conflict, you said that you have given the same name to both, change that, so that they are different. – Suleyman May 28 '18 at 07:30
  • when i used postpone enter transition on button clcik it kind of freezes and i gave same name because in most of the youtube tuts they gave same name – cooldev May 28 '18 at 08:20

1 Answers1

0

I post it as an answer because it's a bit long. You are right, if you want to share, for example, one image between a Fragment and an Activity you need to provide the same name in both. But in your case, you have a RecyclerView which can have many elements and therefore you need to provide a unique transition name to each one. A good place to do it is onBindViewHolder where you can set the transition name by appending the position, for example:

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    imageView.setTransitionName("YourTransitionName" + position);
    // other code
}

That way you are sure that each transition name is unique and therefore there is no conflict. As you already know you need to set the transition name in both places, so you will need to pass the position to your ViewPager. Also, check out this article it may help.

Suleyman
  • 2,765
  • 2
  • 18
  • 31
  • Ok that makes sense and as you can see in my viewholder class i'm passing layout position of recyclerview and it sends the proper image so for animation should i make any changes – cooldev May 28 '18 at 09:04
  • @cooldev I don't think so, just make sure that you append the position to the transition name in both places. – Suleyman May 28 '18 at 09:13
  • Hi i set transitionname in onBindviewholder still it is same i also appended the position but no difference – cooldev May 28 '18 at 09:32
  • @cooldev you appended it in both places? in Fragment and in Activity as well? – Suleyman May 28 '18 at 09:33
  • I'm appending the position in fragment and in detail activity i'm getting that image through intent and setting it to viewpager – cooldev May 28 '18 at 09:49
  • @cooldev Check if the positions are the same in Activity and in Fragment, so that you set the same transition name. And also I think you need to enable `windowContentTransitions`, it's explained in [this](http://mikescamell.com/shared-element-transitions-part-1/) link that I provided. – Suleyman May 28 '18 at 09:58
  • Ok but i have already set windowContentTransition to true you can check in my question as well and i think i'm getting same position because i 'm receiving the same image in viewpager as well – cooldev May 28 '18 at 10:04
  • and mikescamell's tutorial is the very first tutorial i saw – cooldev May 28 '18 at 10:05
  • @cooldev I didn't notice the `styles.xml`. It's important to make sure that the transition name is the same by using Logs or something else because it usually is the problem. To be honest, I'm not too sure about Fragment to Activity transition, you will have much less headache with Fragment to Fragment or Activity to Activity. I can suggest [this post](https://stackoverflow.com/questions/38593474/how-to-shared-element-transition-from-a-fragment-to-an-activity), it may help. – Suleyman May 28 '18 at 10:15
  • @cooldev I don't think so but it may be due to the fact the Views are not ready when the transition is ready, so you need to postpone (usually in `onCreate`) and then start it when the Views are ready, it's explained [here](https://www.androiddesignpatterns.com/2015/03/activity-postponed-shared-element-transitions-part3b.html) – Suleyman May 28 '18 at 10:57
  • I tried using postpone but when i click recyclerview it somewhat freezes i dont know why – cooldev May 28 '18 at 10:58
  • @cooldev But you have to call it in the right place, and after you call it, in order to start the transition you have to call `startPostponedEnterTransition()`, the mechanics of it is explained in the article. For example, in my case I have Fragment to Fragment transition, I postpone it in `onCreate` and start it in the callback method of Glide, in your case it would be tree observer, as explained in the article. – Suleyman May 28 '18 at 11:07