简体   繁体   English

如何使用从 RecyclerView 到 Fragment 的共享转换

[英]How to used a shared transition from RecyclerView to a Fragment

I've seen this questioned asked a number of times on here without an answer.我已经看到这个问题在这里问了很多次没有答案。 I'm hoping if I ask it again maybe someone will be kind enough to help me with it.我希望如果我再问一次,也许有人会好心地帮助我。

I'm trying to implement a shared transition from an Item in a Recyclerview to a fragment.我正在尝试实现从 Recyclerview 中的项目到片段的共享转换。

I currently have my fragment transaction in the onBindView method of the adapter.我目前在适配器的 onBindView 方法中有我的片段事务。

public void onClick(View v) {
    ...
    activity.getSupportFragmentMnager().beginTransaction()
            .addSharedElement(v, "SharedString")
            .replace(R.id.container, fragment2)
            .addToBackStack(null)
            .commit();
}

In the android docs , addSharedElement(view and string) confuse me.android docs 中, addSharedElement(view and string) 让我感到困惑。 How do I give the view a unique ID and should I even be using v here?我如何给视图一个唯一的 ID,我应该在这里使用 v 吗?

Can the string be what ever I want?字符串可以是我想要的吗?

here is my implementation.这是我的实现。 There is FragmentList with RecyclerView with images on each item.有带有RecyclerView FragmentList ,每个项目上都有图像。 And there is FragmentDetail with only on big image.并且只有在大图像上才有FragmentDetail Image from FragmentList list item fly to FragmentDetail .图像从FragmentList列表项飞到FragmentDetail TransitionName of animated view on FragmentList and FragmentDetail must be same. FragmentListFragmentDetail上动画视图的TransitionName必须相同。 So I give unique transition name for each list item ImageView:所以我为每个列表项 ImageView 指定了唯一的过渡名称:

imageView.setTransitionName("anyString" + position)

Then I pass that string to FragmentDetail via setArguments and set big image transitionName to that string.然后我通过setArguments将该字符串传递给FragmentDetail并将大图像transitionName设置为该字符串。 Also we should provide Transition which describes how view from one view hierarchy animates to another viewhierarchy.此外,我们应该提供Transition来描述从一个视图层次结构的视图如何动画到另一个视图层次结构。 After that we should pass that transition to fragment.之后,我们应该将该transition给片段。 I do it before FragmentTransaction :我在FragmentTransaction之前这样做:

 detailFragment.setSharedElementEnterTransition(getTransition());
 detailFragment.setSharedElementReturnTransition(getTransition());

Or you can override getSharedElementEnterTransition and getSharedElementReturnTransition of Fragment and declare transition there.或者您可以覆盖Fragment getSharedElementEnterTransitiongetSharedElementReturnTransition并在那里声明transition Here is full code:这是完整的代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(savedInstanceState == null) {
            getSupportFragmentManager()
                    .beginTransaction()
                    .replace(R.id.fragment_container, new FragmentList())
                    .commit();
        }
    }

    public void showDetail(View view) {
        String transitionName = view.getTransitionName();

        FragmentDetail fragment = new FragmentDetail();
        fragment.setArguments(FragmentDetail.getBundle(transitionName));
        fragment.setSharedElementEnterTransition(getTransition());
        fragment.setSharedElementReturnTransition(getTransition());

        getSupportFragmentManager()
                .beginTransaction()
                .addSharedElement(view, transitionName)
                .replace(R.id.fragment_container, fragment)
                .addToBackStack(null)
                .commit();
    }

    private Transition getTransition() {
        TransitionSet set = new TransitionSet();
        set.setOrdering(TransitionSet.ORDERING_TOGETHER);
        set.addTransition(new ChangeBounds());
        set.addTransition(new ChangeImageTransform());
        set.addTransition(new ChangeTransform());
        return set;
    }
}

activity_main.xml活动_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" />

FragmentList:片段列表:

public class FragmentList extends Fragment {

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_list, container, false);
        RecyclerView rv = view.findViewById(R.id.recyclerview);
        rv.setAdapter(new ListAdapter());
        return view;
    }

    private class ListAdapter extends RecyclerView.Adapter {
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
            return new Holder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            Holder hold = (Holder) holder;
            hold.itemView.setOnClickListener(v -> {
                ((MainActivity) getActivity()).showDetail(hold.imageView);
            });
            //unique string for each list item
            hold.imageView.setTransitionName("anyString" + position);
        }

        @Override
        public int getItemCount() {
            return 10;
        }

        private class Holder extends ViewHolder {
            ImageView imageView;

            public Holder(View view) {
                super(view);
                imageView = view.findViewById(R.id.image);
            }
        }
    }
}

fragment_list.xml片段列表.xml

<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

FragmentDetail:片段详细信息:

public class FragmentDetail extends Fragment {
    private static final String NAME_KEY = "key";

    public static Bundle getBundle(String transitionName) {
        Bundle args = new Bundle();
        args.putString(NAME_KEY, transitionName);
        return args;
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_detail, container, false);
        String transitionName = getArguments().getString(NAME_KEY);
        ImageView imageView = view.findViewById(R.id.image);
        imageView.setTransitionName(transitionName);
        return view;
    }
}

fragment_detail.xml fragment_detail.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <ImageView
        android:id="@+id/image"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:src="@drawable/cat"/>
</LinearLayout>

item.xml项目.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center">

    <ImageView
        android:id="@+id/image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/cat"/>
</LinearLayout>

Here is result:这是结果:

在此处输入图片说明

TransitionName may be any string you want. TransitionName可以是您想要的任何字符串。 There is ViewCompat.setTransitionName if you need support pre Lollipop devices.如果您需要支持 Lollipop 前设备,则可以使用ViewCompat.setTransitionName

Adding to the ashakirov's answer :添加到ashakirov 的回答中

Problem问题

Return Transition was not working!返回转换不起作用!

Reason: On popbackstack from Fragment B to Fragment A , Fragment A's onCreateView is called and if your data is still loading then the return transition won't work with only ashakirov's code.原因:在从Fragment BFragment A popbackstackFragment A's onCreateView 被调用,如果您的数据仍在加载,则返回转换仅适用于 ashakirov 的代码。

Solution解决方案

Postpone the transition in your fragments推迟片段中的过渡

Add this line where the loading starts in your fragment A :fragment A添加开始加载的这一行:

postponeEnterTransition();

After your data is loaded or you've set your adapter, write this:加载数据或设置适配器后,请编写以下内容:

startPostponedEnterTransition();

This ensures that your transition only happens after your data is loaded.这确保您的转换仅在您的数据加载后发生。 Also, make sure you start the transition even in 'data failed to load scenarios'.此外,请确保即使在“数据加载失败的场景”中也开始转换。

If you want to postpone the transition in your fragment B when going from A to B then add this to your fragment B :如果您想在从A to B时推迟fragment B的转换,请将其添加到您的fragment B

@Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        //hold the transition
        postponeEnterTransition();
        //when the views are available then start the transition
        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                view.getViewTreeObserver().removeOnPreDrawListener(this);
                startPostponedEnterTransition();
                return true;
            }
        });
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 共享元素从viewPager中的recyclerView转换为fragment - Shared elements transition from recyclerView in viewPager to fragment Jetpack Navigation 中从 RecyclerView 到 Detail Fragment 的共享元素转换 - Shared element transition in Jetpack Navigation from RecyclerView to Detail Fragment 共享元素从viewpager内的fragment recyclerview过渡到新活动? - Shared element transition from fragment recyclerview inside viewpager to new activity? 如何使用 Android 导航组件实现从 RecyclerView 项目到 Fragment 的共享过渡元素? - How to implement shared transition element from RecyclerView item to Fragment with Android Navigation Component? 如何共享元素从片段到活动的转换 - how to Shared element transition from a fragment to an activity 共享转换不能将recyclerview用于片段 - Shared Transition doesn't work recyclerview to fragment Android:RecyclerView和Fragment之间没有共享元素转换 - Android: No shared element transition between RecyclerView and Fragment 如何从ViewPager到另一个片段进行共享过渡动画? - How to make shared transition animation from ViewPager to another Fragment? 从RecyclerView到活动的共享元素过渡不起作用 - Shared element transition from RecyclerView to activity not working 如何在RecyclerView中将共享元素转换为onClickListener? - How to implement shared element transition to onClickListener in RecyclerView?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM