共享元素转换+片段+ RecyclerView + ViewPager

时间:2018-04-12 21:53:46

标签: android android-fragments android-viewpager android-glide android-transitions

我正在实施一个图库应用程序,其中包含一个片段,其中包含带有图像的RecyclerView,点击我前往ViewPager循环查看图像的图像。
目前,我正在尝试实现像this视频中的输入动画。问题是动画不起作用,我显然缺少一些东西(只显示与转换相关的代码):

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:

@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中的单个图像)中我有:

@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;
}

转换名称不是问题,它是唯一的,并且它在所有片段之间正常传递。我已经关注this文章并阅读了许多其他文章,但感觉我的代码中缺少一点点。

修改
我能够将我认为的问题本地化。转换是随机工作的几次,显然,这是因为当我进行转换时图像还没有准备好。我尝试在MainActivity postponeEnterTransition()中调用onCreate,但仍然无效。图像通过Bundle传递到ImageFragment。还在寻找。

修改

我相信我发现了问题,我有一个片段,里面有一个TabLayout,里面有2个片段,一个显示所有照片,另一个显示标记为收藏的照片。他们都使用相同的RecyclerView。共享元素转换仅在照片同时位于一个部分时才有效,一旦我将照片标记为收藏,它会出现在所有照片中以及收藏的照片中,并且转换不再有效。这可能是因为过渡不再是唯一的。有办法解决这个问题吗?考虑到这两个片段使用相同的RecyclerView和相同的适配器类。

1 个答案:

答案 0 :(得分:1)

我终于开始工作,问题出在过渡名称上。转换也与支持Transition库一起使用 起初,转换根本不起作用,因此我使用了一种方法,我发现here推迟了转换,它是解释转换的一个很好的链接:

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

就我而言,我有嵌套片段,ViewPagerFragment包含ViewPager并使用ImageFragment管理片段(ImageAdapter)。我从postponeEnterTransition()致电ViewPagerFragment,这就是我使用getParentFragment()的原因。

我在Glide scheduleStartPostoponedTransitiononLoadFailed中使用了onResourceReady()方法 主要问题在于我的实施。我有一个包含TabLayout的片段,其中包含2个制表符,每个制表符包含一个带有RecyclerView的片段。一个片段显示所有照片和其他显示最喜欢的照片。如果照片只在一个标签中,过渡工作正常(在我上面提到的一些改动之后),但是一旦我将其标记为收藏,它就不会在任一标签中工作。这意味着两个标签的照片具有相同的过渡名称 我的解决方案是将整数传递给GridAdapter,具体取决于显示的片段(所有照片为1,最喜欢的照片为2)并将其设置为过渡名称:

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或更高版本,因为它们修复了此版本中的转换。