共享元素返回过渡不适用于片段中的 recyclerview 和 cardview

Posted

技术标签:

【中文标题】共享元素返回过渡不适用于片段中的 recyclerview 和 cardview【英文标题】:Shared element back transition not working with recyclerview and cardviews in fragments 【发布时间】:2020-12-31 14:40:07 【问题描述】:

我正在尝试在具有 cardviews 片段的回收器视图与仅包含 1 张卡的片段之间创建过渡。问题是返回转换不起作用,而输入转换起作用。如果我删除setReorderingAllowed(true);,则返回转换正在工作,但输入转换停止工作。 这就是我所拥有的。

带有 recyclerview 和 cardviews 的片段

public class OrdersFragment extends Fragment implements OrderAdapter.OnOrderListener 

    private OrderAdapter mAdapter;

    private TextView bonnenTextView;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        postponeEnterTransition();
    

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment_bonnen, container, false);
        bonnenTextView = view.findViewById(R.id.bonnen_text_view);
        RecyclerView orderRecyclerView = view.findViewById(R.id.order_recycler_view);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
        orderRecyclerView.setLayoutManager(layoutManager);
        if (mAdapter == null) 
            mAdapter = new OrderAdapter(this);
            fetchOrders();
        
        orderRecyclerView.setAdapter(mAdapter);
        return view;
    

    private void fetchOrders() 
        new OrderFetcher().fetch(new Callback() 
            @Override
            public void onComplete(Result result) 
                if (result instanceof Result.Success) 
                    mAdapter.setOrders((Order[]) ((Result.Success<?>)result).data);
                    mAdapter.notifyDataSetChanged();
                 else 
                    Toast.makeText(getContext(), "Could not load orders", Toast.LENGTH_SHORT).show();
                
                startPostponedEnterTransition();
            
        );
    

    @Override
    public void onOrderClick(int position, View view, Order order) 
        Log.i("OrderClick", "Transition name " + view.getTransitionName());

        View carrierTextView = view.findViewById(R.id.carrier_text_view);
        View numberTextView = view.findViewById(R.id.id_text_view);
        View pickerTextView = view.findViewById(R.id.picker_text_view);
        View locationTextView = view.findViewById(R.id.location_text_view);

        FragmentTransaction transaction = getParentFragmentManager().beginTransaction();
        transaction.addSharedElement(view, view.getTransitionName());
        transaction.addSharedElement(carrierTextView, carrierTextView.getTransitionName());
        transaction.addSharedElement(numberTextView, numberTextView.getTransitionName());
        transaction.addSharedElement(pickerTextView, pickerTextView.getTransitionName());
        transaction.addSharedElement(locationTextView, locationTextView.getTransitionName());
        transaction.addSharedElement(bonnenTextView, bonnenTextView.getTransitionName());
        transaction.replace(R.id.nav_host_fragment, BonFragment.newInstance(view.getTransitionName(), order));
        transaction.addToBackStack(null);
        transaction.setReorderingAllowed(true);
        transaction.commit();
    

上面片段的xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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_
    android:layout_
    android:orientation="vertical"
    tools:context=".ui.orders.OrdersFragment">

    <TextView
        android:id="@+id/bonnen_text_view"
        android:transitionName="bonnen_text_view"
        android:layout_
        android:layout_
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:text="@string/orders"
        android:textColor="@color/secondary"
        android:textSize="40sp"
        android:textStyle="bold"
        android:typeface="normal" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/order_recycler_view"
        android:layout_
        android:layout_
        android:layout_margin="20dp"/>
</LinearLayout>

带有单个卡片视图的片段

public static BonFragment newInstance(String cardTransitionName, Order order) 
        BonFragment bonFragment = new BonFragment();

        Bundle args = new Bundle();
        args.putParcelable("orderParcel", order);
        args.putString("cardTransitionName", cardTransitionName);
        bonFragment.setArguments(args);

        return bonFragment;
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 
        final View root = inflater.inflate(R.layout.fragment_bon, container, false);

        CardView orderCard = root.findViewById(R.id.order_card);
        TextView carrierTextView = root.findViewById(R.id.carrier_text_view);
        TextView numberTextView = root.findViewById(R.id.id_text_view);
        TextView pickerTextView = root.findViewById(R.id.picker_text_view);
        TextView locationTextView = root.findViewById(R.id.location_text_view);

        if (getArguments() != null && getArguments().getParcelable("orderParcel") != null) 
            Order order = getArguments().getParcelable("orderParcel");
            orderCard.setTransitionName(getArguments().getString("cardTransitionName"));
            if (order != null) 
                carrierTextView.setTransitionName("carrier" + order.getIndex());
                carrierTextView.setText(order.getCarrier());
                numberTextView.setTransitionName("number" + order.getIndex());
                numberTextView.setText(String.valueOf(order.getNumber()));
                pickerTextView.setTransitionName("picker" + order.getIndex());
                pickerTextView.setText(order.getPicker());
                locationTextView.setTransitionName("location" + order.getIndex());
                locationTextView.setText(order.getPosition());

                carrierTextView.setText("Lorem Ipsum");
                numberTextView.setText("Dolor sit amet");
                pickerTextView.setText("consectetur adipiscing elit");
                locationTextView.setText("Mauris semper");

            
        

        orderCard.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                getParentFragmentManager().popBackStack();
            
        );

        Transition transition = TransitionInflater.from(getContext()).inflateTransition(R.transition.card_transition);
        setSharedElementEnterTransition(transition);
        setSharedElementReturnTransition(transition);
        return root;
    

上面片段的xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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_
    android:layout_
    android:orientation="vertical"
    tools:context=".ui.orders.OrdersFragment">

    <TextView
        android:transitionName="bonnen_text_view"
        android:layout_
        android:layout_
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:text="@string/orders"
        android:textColor="@color/secondary"
        android:textSize="40sp"
        android:textStyle="bold"
        android:typeface="normal" />

    <androidx.cardview.widget.CardView
        android:id="@+id/order_card"
        android:layout_
        android:layout_
        app:cardBackgroundColor="@color/primaryLight"
        android:foreground="?android:attr/selectableItemBackground"
        android:clickable="true"
        android:layout_margin="25dp">

        <LinearLayout
            android:transitionName="order_card_layout"
            android:layout_
            android:layout_
            android:orientation="vertical"
            android:layout_margin="10dp">
            <TextView
                android:id="@+id/carrier_text_view"
                android:transitionName="carrier_text_view"
                android:layout_
                android:layout_
                android:textColor="@color/secondary"
                android:textSize="20sp"
                android:textStyle="bold"/>
            <TextView
                android:id="@+id/id_text_view"
                android:transitionName="id_text_view"
                android:layout_
                android:layout_
                android:textColor="@color/secondary" />
            <TextView
                android:id="@+id/picker_text_view"
                android:transitionName="picker_text_view"
                android:layout_
                android:layout_
                android:textColor="@color/secondary" />
            <TextView
                android:id="@+id/location_text_view"
                android:transitionName="location_text_view"
                android:layout_
                android:layout_
                android:textColor="@color/secondary" />
        </LinearLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

这就是setReorderingAllowed(true); 的样子

这就是没有setReorderingAllowed(true);的样子

编辑 在应用 ianhanniballake 给出的答案后,我得到了它的工作。 这是我为将来参考所做的。 我所做的唯一更改是在 OrdersFragment 类中。 我删除了 onCreate() 方法的覆盖。 我从 fetchOrders() 方法中删除了 startPostponedEnterTransition(); 并添加了

@Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
        postponeEnterTransition();
        final ViewGroup parentView = (ViewGroup) view.getParent();
        parentView.getViewTreeObserver()
                .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() 
                    @Override
                    public boolean onPreDraw() 
                        parentView.getViewTreeObserver().removeOnPreDrawListener(this);
                        startPostponedEnterTransition();
                        return true;
                    
                );
        super.onViewCreated(view, savedInstanceState);
    

就是这样

【问题讨论】:

【参考方案1】:

根据Use shared element transitions with a RecyclerView guide,您调用startPostponedEnterTransition() 为时过早-在设置数据后(并调用notifyDataSetChanged() 通知适配器),您需要等到RecyclerView 被实际测量和铺设出去。这要求您添加一个OnPreDrawListener,并且只有在触发时才调用startPostponedEnterTransition()

【讨论】:

【参考方案2】:

在 Kotlin 中,您需要在 recyclerView 的 doOnPreDraw 回调中启动转换,如下所示:

recyclerView.doOnPreDraw 
    startPostponedEnterTransition()

【讨论】:

以上是关于共享元素返回过渡不适用于片段中的 recyclerview 和 cardview的主要内容,如果未能解决你的问题,请参考以下文章

片段之间的共享元素转换

使用片段共享过渡时返回过渡无法正常工作

如何共享元素从片段到活动的过渡

导航组件共享元素转换适用于输入,但不适用于弹回

5秒后Android返回过渡不起作用

如何实现与视频的共享元素过渡