共享元素过渡+片段+ RecyclerView + ViewPager [英] Shared Element Transition + Fragment + RecyclerView + ViewPager

查看:418
本文介绍了共享元素过渡+片段+ RecyclerView + ViewPager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现一个图库应用程序,该应用程序具有一个Fragment,其中包含带有图像的RecyclerView,图像的onClick,我转到ViewPager来循环浏览图像.
目前,我正在尝试仅实现视频中的输入动画.问题是动画无法正常工作,我显然缺少了一些东西(只是显示与转场相关的代码):

I am implementing a gallery app, which has a Fragment that holds a RecyclerView with images, onClick of an image I go to ViewPager to cycle through images.
For now, I am trying to implement just the entry animation like in this video. The problem is the animation just doesn't work, I am obviously missing something (just showing code which is relevant to transitions):

ViewPager:

public class ViewPagerFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_viewpager, container, false);
        Transition transition = TransitionInflater.from(getContext()).inflateTransition(R.transition.fragment_transition);

        setSharedElementEnterTransition(transition);
        postponeEnterTransition();
        return view;
}

GridAdapter:

public class GridAdapter extends RecyclerView.Adapter<GridAdapter.ViewHolder> {

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.setPhotoImage(new File(mArrayOfPhotos.get(position).photo));
        ViewCompat.setTransitionName(holder.photoImage, mPhotoObjects.get(position).photo);
    }

    @Override
    public void onClick(View view) {
        // pass an image view that is being clicked... 
        // ...via listener to MainActivity from where ViewPagerFragment is started
        mListener.onImageSelected(photoImage, getAdapterPosition());
    }
}

在MainActivity中,我在onClick上实例化ViewPagerFragment:

In MainActivity I instantiate ViewPagerFragment in onClick:

@Override
public void onImageSelected(View view, int clickedImagePosition) {
    ViewPagerFragment fragment = new ViewPagerFragment();
    Bundle bundle = new Bundle();
    bundle.putInt(ViewPagerFragment.KEY_IMAGE_INDEX, clickedImagePosition);
    fragment.setArguments(bundle);
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    // view is an image view that was clicked
    fragmentTransaction.addSharedElement(view, ViewCompat.getTransitionName(view));
    fragmentTransaction.setReorderingAllowed(true);
    fragmentTransaction.replace(R.id.fragment_placeholder, fragment, VIEWPAGER_FRAGMENT);
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();
}

最后在ImageFragment(这是ViewPager中的单个图像)中,我有:

And finally in ImageFragment(which is a single image in ViewPager) I have:

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    mFullImage.setTransitionName(transitionName);

    Glide.with(getActivity())
            .load(myImage)
            .apply(new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
            .listener(new RequestListener<Drawable>() {
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                    getParentFragment().startPostponedEnterTransition();
                    return false;
                }

                @Override
                public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                    getParentFragment().startPostponedEnterTransition();
                    return false;
                }
            })
            .into(mFullImage);

    return view;
}

过渡名称不是问题,它是唯一的,并且通常在所有片段之间传递.我遵循了文章并阅读了许多其他文章,但是感觉我的代码中缺少了一点点.

Transition name is not the problem, it is unique, and it is passed normally between all the fragments. I have followed this article and read many others, but it feels like a small bit is missing in my code.


我能够定位我认为的问题.过渡随机进行了几次,显然是因为我进行过渡时图像尚未准备就绪.我试图在MainActivity onCreate中调用postponeEnterTransition(),但仍然无法正常工作.图像通过捆绑包传递到ImageFragment.还在寻找.


I was able to localize the problem I think. The transition worked several times randomly, apparently, it happens because images are not ready when I am making the transition. I tried to call postponeEnterTransition() in MainActivity onCreate but still doesn't work. Images are passed to the ImageFragment through the Bundle. Still looking.

我相信我发现了问题,我有一个片段,里面有一个TabLayout,其中有2个片段,一个显示所有照片,另一个显示被标记为收藏的照片.而且它们都使用相同的RecyclerView.仅当照片同时在一个区域中时,共享元素过渡才起作用,一旦我将照片标记为收藏,它就会出现在所有照片以及收藏的照片中,并且过渡不再起作用.发生这种情况的原因可能是过渡不再是唯一的.有办法解决吗?考虑到两个片段使用相同的RecyclerView和相同的适配器类的事实.

I believe I found the problem, I have a fragment, that has a TabLayout inside it, which has 2 fragments, one displaying all photos, and one displaying photos that are tagged as favorite. And they both use the same RecyclerView. The shared element transition works only if the photo is in one section at the same time, once I tag a photo as favorite it appears in all photos as well as favorite photos and the transition no longer works. It probably happens because the transition is no longer unique. Is there a way to solve this? Considering the fact that both fragments use the same RecyclerView, and the same adapter class.

推荐答案

我终于开始使用它了,问题出在过渡名称中.过渡也可以与支持Transition库一起使用.
最初,过渡根本无法正常工作,因此我使用了一种找到

I finally got it to work, the problem was in transition names. The transitions are also working with the support Transition library.
At first, the transition was not working at all, so I used a method that I found here to postpone the transition, it's a good link that explains transitions:

private void scheduleStartPostponedTransition(final View sharedElement) {
sharedElement.getViewTreeObserver().addOnPreDrawListener(
    new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
            getParentFragment().startPostponedEnterTransition();
            return true;
        }
    });
}

就我而言,我有嵌套的片段,一个包含ViewPager并使用ImageAdapter管理片段(ImageFragment)的ViewPagerFragment.我从ViewPagerFragment呼叫postponeEnterTransition(),这就是为什么我使用getParentFragment()的原因.

In my case, I have nested fragments, a ViewPagerFragment that contains a ViewPager and manages the fragments (ImageFragment) using ImageAdapter. I call postponeEnterTransition() from the ViewPagerFragment and that is why I am using getParentFragment().

我在Glide onLoadFailedonResourceReady()中使用了方法scheduleStartPostoponedTransition.
主要的问题是在我的实施中.我有一个包含TabLayout的片段,该片段带有2个选项卡,每个选项卡都包含一个带有RecyclerView的片段.一个片段显示所有照片,其他片段显示收藏的照片.如果照片仅在一个选项卡中,则过渡效果很好(经过我上面提到的一些更改后),但是一旦我将其标记为我的收藏",它就不会在任何一个选项卡中都起作用.这意味着两个选项卡上的照片具有相同的过渡名称.
我的解决方案是根据显示的片段将整数传递给GridAdapter(对于所有照片均为1,对于喜欢的照片为2),并将其设置为过渡名称:

I used the method scheduleStartPostoponedTransition in Glide onLoadFailed and onResourceReady().
The main problem was in my implementation. I have a fragment that contains a TabLayout with 2 tabs, each containing a fragment with a RecyclerView. One fragment shows all photos and other shows favorite photos. The transitions were working fine (after some alteration that I mentioned above) if a photo was only in one tab, but as soon as I marked it as favorite, it wouldn't work in either tab. Which means that two tabs had a photo with the same transition name.
My solution was to pass an integer to the GridAdapter depending on which fragment was shown (1 for all photos and 2 for favorite photos) and set it as a transition name:

public class GridAdapter extends RecyclerView.Adapter<GridAdapter.ViewHolder> {

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.setPhotoImage(new File(mArrayOfPhotos.get(position).photo));
        ViewCompat.setTransitionName(holder.photoImage, mPhotoObjects.get(position).photo + fragmentNumber);
    }
}

,然后将此数字传递给ImageFragment并将其设置在那里.之后,它开始工作,因为现在每张照片都有一个不同的过渡名称.
另外,如果您使用的是过渡版本的支持版本,请确保您具有支持库版本27.0.0或更高版本,因为它们已修复了该版本中的过渡版本.

And then pass this number to the ImageFragment and set it there too. After that, it started to work because every photo now had a different transition name.
Also if you are using a support version of transitions make sure you have the support library version 27.0.0 or above, as they fixed the transitions in this version.

这篇关于共享元素过渡+片段+ RecyclerView + ViewPager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆