如何使用从 RecyclerView 到 Fragment 的共享转换 [英] How to used a shared transition from RecyclerView to a Fragment

查看:39
本文介绍了如何使用从 RecyclerView 到 Fragment 的共享转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到这个问题在这里问了很多次没有答案.我希望如果我再问一次,也许有人会好心地帮助我.

我正在尝试实现从 Recyclerview 中的项目到片段的共享转换.

我目前在适配器的 onBindView 方法中有我的片段事务.

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

TransitionName 可以是您想要的任何字符串.有 ViewCompat.setTransitionName 如果你需要支持 pre Lollipop 设备.

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.

I currently have my fragment transaction in the onBindView method of the adapter.

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. How do I give the view a unique ID and should I even be using v here?

Can the string be what ever I want?

解决方案

here is my implementation. There is FragmentList with RecyclerView with images on each item. And there is FragmentDetail with only on big image. Image from FragmentList list item fly to FragmentDetail. TransitionName of animated view on FragmentList and FragmentDetail must be same. So I give unique transition name for each list item ImageView:

imageView.setTransitionName("anyString" + position)

Then I pass that string to FragmentDetail via setArguments and set big image transitionName to that string. Also we should provide Transition which describes how view from one view hierarchy animates to another viewhierarchy. After that we should pass that transition to fragment. I do it before FragmentTransaction:

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

Or you can override getSharedElementEnterTransition and getSharedElementReturnTransition of Fragment and declare transition there. 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

<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

<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

<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

<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. There is ViewCompat.setTransitionName if you need support pre Lollipop devices.

这篇关于如何使用从 RecyclerView 到 Fragment 的共享转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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