父元素和子片段(嵌套片段)之间的共享元素过渡不起作用 [英] Shared Element Transition Not Working Between Parent and Child Fragments (Nested Fragments)

查看:84
本文介绍了父元素和子片段(嵌套片段)之间的共享元素过渡不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在主活动中,我有BottomNavigationView,其中有3个不同的父片段.父片段具有recyclerview,在单击recyclerview的项目时,我将启动子片段以获取有关该项目的更多详细信息.我正在尝试在两个片段(父级和子级)之间实现Shared Element Transition,但是没有实现.

In the Main Activity, I have BottomNavigationView where there are 3 different parent fragments. The parent fragment has recyclerview and on item click of recyclerview, I am launching child fragment for more details about the item. I am trying to implement Shared Element Transition between my two fragments (parent & child) but it's not happening.

启动子片段也没有问题,我已经检查了过渡名称,并且在子片段中分配了相同的名称,该片段分配给适配器中的项目.我正在使用Random类将过渡名称分配给项目,因为在单个父片段中,我有很多recyclerviews.这是我的代码:

There is no issue with launching child fragment also I have checked the transition name and it's the same in child fragment which I assign to an item in the adapter. I am using Random class to assign transition name to item as in single parent fragment I have many recyclerviews. Here is my code:

适配器

    final String transition;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        transition = "transition" + new Random().nextInt(9999999);
        viewHolder.image.setTransitionName(transition);
    }
    viewHolder.container.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mCallback.itemClicked(i, book, viewHolder.image, transition);
        }
    });

父母片段

@Override
public void itemClicked(int pos, Book book, View view, String transition) {
    MainActivity activity = (MainActivity) getActivity();
    ChildFragment myFragment = new ChildFragment();
    Bundle bundle = new Bundle();
    bundle.putString(IntentExtraKeys.TRANSITION_NAME, transition);
    myFragment.setArguments(bundle);
    activity.showFragmentWithTransition(this, myFragment, ChildFragment.class.getName(), view, transition);
}

活动

public void showFragmentWithTransition(Fragment current, Fragment newFragment, String tag, View sharedView, String sharedElementName) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        current.setSharedElementReturnTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
        current.setExitTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.no_transition));
        newFragment.setSharedElementEnterTransition(TransitionInflater.from(this).inflateTransition(R.transition.default_transition));
        newFragment.setEnterTransition(TransitionInflater.from(this).inflateTransition(android.R.transition.no_transition));
    }

    FragmentManager manager = current.getChildFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.replace(R.id.child_fragment, newFragment, tag);
    transaction.addToBackStack(tag);
    transaction.addSharedElement(sharedView, sharedElementName);
    transaction.commit();
}

默认过渡

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeTransform />
    <changeBounds />
</transitionSet>

儿童片段

    Bundle b = getArguments();
    if (b != null) {
        String transitionName = b.getString(IntentExtraKeys.TRANSITION_NAME);
        Logger.info("opening bundle book fragment:" + transitionName);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            image.setTransitionName(transitionName);
        }
    }

这是问题的样本项目: https://gitlab.com/iskfaisal/transition-issue

Here is the sample project of issue: https://gitlab.com/iskfaisal/transition-issue

推荐答案

我正在尝试在我的两个片段(父级和子级)之间实现共享元素转换,但是这没有发生.

I am trying to implement Shared Element Transition between my two fragments (parent & child) but it's not happening.

什么也没有发生,或者至少看起来好像什么也没有发生,因为您只在 default_transition.xml 中使用了<changeTransform/><changeBounds />.如果两个Fragments 巧合的边界,则没有任何过渡".

Nothing is happening or at least it looks like nothing is happening because you're using only <changeTransform/> and <changeBounds /> in your default_transition.xml. If bounds of both Fragments coincide, there's nothing to "transit".

但是,如果向文件中添加其他动画元素,则过渡实际上是可见的(即使边界重合).

However, if you add additional animation elements to the file then the transition is actually visible (even if bounds coincide).

我创建了一个与您的项目相似的示例项目-BottomNavigationView,其中的NavHostFragment包含2父级Fragments-DashboardFragmentHomeFragment.

I have created a sample project similar to yours - BottomNavigationView with a NavHostFragment containing 2 parent Fragments - DashboardFragment and HomeFragment.

最初,DashboardFragment加载由简单的RecyclerView组成的DashboardListFragment.如果单击任何RecyclerView项,则DashboardFragment加载DashboardDetailFragment(DashboardDetailFragmentDashboardListFragment中的边界重合).

Initially, DashboardFragment loads DashboardListFragment that consists of a simple RecyclerView. If any RecyclerView item is clicked then DashboardFragment loads DashboardDetailFragment (bounds in DashboardDetailFragment and DashboardListFragment coincide).

然后,我几乎重用了您的showFragmentWithTransition(...),并尝试单击列表中的每个元素以检查是否可以看到任何过渡-事实并非如此.

Then, I pretty much reused your showFragmentWithTransition(...) and tried to click each element in the list to check if any transition would be visible - it wasn't.

因此,我通过添加一个简单的<slide/>元素来修改文件,如下所示:

Hence, I modified the file by adding a simple <slide/> element as below:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet>
    <slide/>
    <changeTransform />
    <changeBounds />
</transitionSet>

滑动过渡就在那儿.

我还尝试了其他元素,例如<fade/><explode/>或其他-所有这些也都很好用.

I also tried other elements like <fade/> or <explode/> or others - all of them worked just fine too.

即使看不到过渡,也并不意味着过渡没有发生.您应该尝试其他动画元素才能看到它的效果.

Even if a transition is not visible, it doesn't mean it's not happening. You should try other animation elements to see it work.

由于您提供了指向 github 代码的链接,因此我进行了深入研究,并将其置于工作状态.我会把它留给您,以进一步改进它.

Since you provided a link to your github code, I peeked into it and brought it to the working condition. I'll leave it up to you to improve it further.

因此,基本上,您的HomeFragment布局文件同时包含RecyclerView和您的孩子Fragment的占位符.相反,我将您的HomeFragment拆分为2实体-一个用于父级Fragment HomeFragment的实体,该实体仅包含任何子级FragmentHomeFragmentList的占位符,而子级FragmentHomeFragmentList包含您以前的父级逻辑.

So, basically, your HomeFragment layout file contained both RecyclerView and a placeholder for your child Fragment at the same time. Instead, I split your HomeFragment into 2 entities - one for your parent Fragment HomeFragment containing only the placeholder for any child Fragment and HomeFragmentList containing your previous parent logic.

然后,当选择了图像,替换您.而且... 有效

Then, when a picture is selected, HomeFragment replaces your HomeFragmentList with a ChildFragment. And...it works!

通过这种方式,您无需使用Activity来创建子级Fragment,它更加独立.

This way, you don't need to use your Activity for creating a child Fragment and it's more independent.

下面,我提供了必须修改的相关代码.

Below, I provide the relevant code that had to be modified.

public class HomeFragment extends Fragment {

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_home, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        HomeFragmentList homeFragmentList = new HomeFragmentList();
        FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.child_fragment, homeFragmentList, homeFragmentList.getClass().getName());
        fragmentTransaction.commit();
    }
}

HomeFragmentList(老父母)

public class HomeFragmentList extends Fragment implements AdapterListener {
    RecyclerView recyclerView;
    private ArrayList<String> images = new ArrayList<>();

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View root = inflater.inflate(R.layout.fragment_home_list, container, false);

        recyclerView = root.findViewById(R.id.recycler_view);
        getImages();
        LinearLayoutManager manager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
        recyclerView = root.findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(manager);
        AdapterClass adapter = new AdapterClass(this, images);
        recyclerView.setAdapter(adapter);

        return root;
    }

    void getImages() {
        images.add("https://rukminim1.flixcart.com/image/832/832/book/0/1/9/rich-dad-poor-dad-original-imadat2a4f5vwgzn.jpeg?q=70");
        images.add("https://www.seeken.in/wp-content/uploads/2017/06/The-4-Hour-Work-Week.jpeg");
        images.add("https://www.seeken.in/wp-content/uploads/2017/06/Managing-Oneself.jpeg");
        images.add("https://www.seeken.in/wp-content/uploads/2017/07/How-to-Win-Friends-and-Influence-People.jpeg");
        images.add("https://www.seeken.in/wp-content/uploads/2017/07/THINK-LIKE-DA-VINCI-7-Easy-Steps-to-Boosting-your-Everyday-Genius.jpeg");
        images.add("https://www.seeken.in/wp-content/uploads/2017/07/How-To-Stop-Worrying-And-Start-Living.jpg");
        images.add("https://www.seeken.in/wp-content/uploads/2017/08/THE-INTELLIGENT-INVESTOR.jpeg");
        images.add("https://www.seeken.in/wp-content/uploads/2017/08/Awaken-the-Giant-within-How-to-Take-Immediate-Control-of-Your-Mental-Emotional-Physical-and-Financial-Life.jpg");
        images.add("https://www.seeken.in/wp-content/uploads/2017/08/E-MYTH-REVISITED.jpeg");
        images.add("https://images-na.ssl-images-amazon.com/images/I/41axGE4CehL._SX353_BO1,204,203,200_.jpg");
        images.add("https://rukminim1.flixcart.com/image/832/832/book/0/1/9/rich-dad-poor-dad-original-imadat2a4f5vwgzn.jpeg?q=70");

    }

    @Override
    public void itemClicked(int pos, ModelClass object, View view, String transition) {
        MainActivity activity = (MainActivity) getActivity();
        ChildFragment myFragment = new ChildFragment();
        Bundle bundle = new Bundle();
        bundle.putString("IMAGE_URL", object.getItem(pos));
        bundle.putInt("POSITION", pos);
        bundle.putString("TRANSITION_NAME", transition);
        myFragment.setArguments(bundle);
        Log.i("HOME FRAGMENT-DEBUG", transition + "/" + view.getTransitionName());
        showFragmentWithTransition(getParentFragment(), myFragment, ChildFragment.class.getName(), view, transition);
    }

    public void showFragmentWithTransition(Fragment current, Fragment _new, String tag, View sharedView, String sharedElementName) {

        FragmentManager manager = current.getChildFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        if (sharedView != null && sharedElementName != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                current.setSharedElementReturnTransition(TransitionInflater.from(getContext()).inflateTransition(R.transition.default_transition));
                current.setExitTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.no_transition));
                _new.setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(R.transition.default_transition));
                _new.setEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.no_transition));
                transaction.addSharedElement(sharedView, sharedElementName);
                Log.i("ACTIVITY-DEBUG", sharedElementName + "/" + sharedView.getTransitionName());
            }
        }
        transaction.replace(R.id.child_fragment, _new, tag);
        transaction.addToBackStack(tag);
        transaction.commit();
    }
}

fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>

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

    <FrameLayout
        android:id="@+id/child_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

fragment_home_list.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FFF">

        <androidx.core.widget.NestedScrollView
            android:id="@+id/home_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="15dp"
                android:layout_marginLeft="9dp"
                android:layout_marginRight="9dp">


                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/recycler_view"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:orientation="vertical">

                </androidx.recyclerview.widget.RecyclerView>

            </RelativeLayout>

        </androidx.core.widget.NestedScrollView>

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#FFF">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/z_toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:elevation="4dp">

                <RelativeLayout
                    android:id="@+id/header_container"
                    android:layout_width="match_parent"
                    android:layout_height="56dp">

                    <ImageView
                        android:id="@+id/logo"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:layout_marginRight="10dp"
                        android:layout_centerVertical="true"
                        android:layout_alignParentLeft="true"
                        android:src="@mipmap/ic_launcher_round"
                        android:contentDescription="@string/app_name" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:layout_toRightOf="@+id/logo"
                        android:textColor="#000"
                        android:textSize="16sp"
                        android:text="Home" />

                </RelativeLayout>

            </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.AppBarLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>

备注

请注意,可以看到<changeTransform/><changeBounds />的过渡,因为HomeFragmentList中选定的View的界限与子Fragment中的界限不同.

Remark

Please note that the transition for <changeTransform/> and <changeBounds /> is visible because bounds of a selected View in HomeFragmentList are different from that in the child Fragment.

这篇关于父元素和子片段(嵌套片段)之间的共享元素过渡不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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