共享元素返回过渡不适用于片段中的 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的主要内容,如果未能解决你的问题,请参考以下文章