【问题标题】:Shared Element Transition + Fragment + RecyclerView + ViewPager共享元素过渡 + 片段 + RecyclerView + ViewPager
【发布时间】:2018-04-12 21:53:45
【问题描述】:

我正在实现一个画廊应用程序,它有一个片段,其中包含一个带有图像的 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 onCreate 中调用 postponeEnterTransition(),但仍然无法正常工作。图像通过 Bundle 传递给ImageFragment。还在寻找。

编辑:

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

【问题讨论】:

  • @Deepakkaku 非常感谢链接,不幸的是,我也检查了它,我关注了我的,因为它更详细和最新。但我也部分地遵循了它。我认为我的代码中有一个小错误。
  • 不起作用是什么意思?它是崩溃的应用程序吗?或者只是没有正确制作动画?如果您链接任何显示动画问题的截屏视频或视频会更好。谢谢!
  • @NileshDeokar 感谢您抽出宝贵时间!根本没有动画,如果我添加共享元素没有区别。我试图更改 XML 文件中的持续时间,但没有更改。我认为由于某种原因甚至没有应用动画。

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


【解决方案1】:

我终于让它工作了,问题出在过渡名称上。过渡也与支持 Transition 库一起使用。
起初,transition根本不起作用,所以我使用了我找到here的方法来推迟transition,这是一个很好的解释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;
        }
    });
}

在我的例子中,我有嵌套的片段,一个 ViewPagerFragment,它包含一个 ViewPager 并使用 ImageAdapter 管理片段 (ImageFragment)。我从ViewPagerFragment 调用postponeEnterTransition(),这就是我使用getParentFragment() 的原因。

我在 Glide onLoadFailedonResourceReady() 中使用了 scheduleStartPostoponedTransition 方法。
主要问题在于我的实施。我有一个包含 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 或更高版本,因为他们在此版本中修复了过渡。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 1970-01-01
    相关资源
    最近更新 更多