从一个包含RecyclerView的片段到另一个片段使用新的导航架构组件进行共享元素转换无法实现。

3

我有一个安卓应用程序,包含2个片段。第一个片段包含一个RecyclerView,用于显示联系人列表。以下是第一个片段的代码:

public class NotesFragment extends Fragment implements ContactsAdapter.OnContactClicked {


    public NotesFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_notes, container, false);
    }

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

        RecyclerView rvContacts = view.findViewById(R.id.rvContacts);
        rvContacts.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));

        List<Contact> contacts = new ArrayList<Contact>(){{
            add(new Contact(1,"Antoine El Murr"));
            add(new Contact(2,"Joelle Abou Chakra"));
            add(new Contact(3,"Michel Jebran"));
            add(new Contact(4,"Charlie Abou Moussa"));
            add(new Contact(5,"Edward Salameh"));
            add(new Contact(6,"Makram Merdass"));
            add(new Contact(7,"Sami Abou Jaoudeh"));
            add(new Contact(8,"Elie Nassif"));
            add(new Contact(9,"Samer Abou Samra"));
            add(new Contact(10,"Fady Ammoury"));
            add(new Contact(11,"Dany Fahed"));
            add(new Contact(12,"Mariana Haddad"));
            add(new Contact(13,"Mohamad Restom"));
        }};

        ContactsAdapter adapter = new ContactsAdapter(contacts);
        adapter.setOnContactClicked(this);
        rvContacts.setAdapter(adapter);

    }

    @Override
    public void onContactClicked(int position, Contact contact, View holderView) {
        NavController navController = Navigation.findNavController(holderView);
        Bundle arguments = new Bundle();
        arguments.putParcelable("contact", contact);
        FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
                .addSharedElement(holderView.findViewById(R.id.tvIcon), ViewCompat.getTransitionName(holderView.findViewById(R.id.tvIcon)))
                .addSharedElement(holderView.findViewById(R.id.tvName), ViewCompat.getTransitionName(holderView.findViewById(R.id.tvName)))
                .build();
        navController.navigate(R.id.ContactToDetails, arguments, null, extras);
    }
}

我正在使用Android Jetpack Navigation组件。在RecyclerView的元素布局文件中,我正在设置每个元素的过渡名称,如下所示:
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content">

    <TextView
        android:id="@+id/tvIcon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:background="@drawable/circular_shape"
        android:gravity="center"
        android:textColor="@android:color/white"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:transitionName="icon"
        tools:text="A" />

    <TextView
        android:id="@+id/tvName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="8dp"
        android:gravity="start"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="@+id/tvIcon"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/tvIcon"
        app:layout_constraintTop_toTopOf="@+id/tvIcon"
        android:transitionName="name"
        tools:text="Antoine El Murr" />

</androidx.constraintlayout.widget.ConstraintLayout>

我在适配器中创建了一个接口,当联系人被点击时触发该函数。

在我的第二个片段中,我已经在XML布局中设置了过渡名称,如下所示:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".ContactDetailsFragment">

    <TextView
        android:id="@+id/tvIcon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:background="@drawable/circular_shape"
        android:gravity="center"
        android:textColor="@android:color/white"
        android:textSize="24sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="A"
        android:transitionName="icon"/>

    <TextView
        android:id="@+id/tvName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="8dp"
        android:gravity="start"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="@+id/tvIcon"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/tvIcon"
        app:layout_constraintTop_toTopOf="@+id/tvIcon"
        tools:text="Antoine El Murr"
        android:transitionName="name"/>

</androidx.constraintlayout.widget.ConstraintLayout>

在onCreate方法中设置进入动画过渡效果,但它没有起作用:
@Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
    }

请帮忙,我在互联网上搜索了解决方法,但是没有成功,所有示例都是关于旧导航系统的。新示例是如何从一个片段到另一个片段使用SharedElements,但不是从RecyclerView,而且安卓官网上的文档很少,也不涵盖使用新导航组件实现此过渡效果的所有步骤。

2个回答

1
我已经找到了问题所在,不要将过渡名称放在 XML 元素内,而是将其放在 ViewHolder(或 Adapter)中,并为回收视图中的每个元素赋予唯一的过渡名称。
例如:
位置 0 的元素 -> 过渡名称 =“image_view_transition_0”
位置 1 的元素 -> 过渡名称 =“image_view_transition_1”
这样,Android 就知道要动画显示哪个元素。如果所有元素具有相同的过渡名称,则会混淆应该对哪个元素进行动画处理。

嘿,但你还必须在另一个片段的元素中命名转换。你怎么命名它?因为在recyclerview中,每个元素都会有不同的转换名称。 - Juan Carlos Durini
你必须通过参数传递每个要进行转换的元素的转换名称,并将传递的转换名称设置为相应的元素。 - Antoine El Murr

0
确保在您的布局之间有匹配的transitionName(s)
android:transitionName="YOUR_TRANSITION_NAME"

然后确保像这样传递共享的视图实例(您也可以使用safeArgs):

some_view.setOnClickListener{
  val extras = FragmentNavigatorExtras(
    yourSharedViewInstance to "YOUR_TRANSITION_NAME"
  )
  findNavController().navigate(R.id.your_destination_action, null, null, extras)
}

然后在你的目的地

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  sharedElementEnterTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move /* or any other transition you want to use */)
}

就是这样 :)


如我所述,我的布局中有匹配的transitionName,并且我正在传递共享视图实例:FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder() .addSharedElement(tvIcon, ViewCompat.getTransitionName(tvIcon)) .addSharedElement(tvName, ViewCompat.getTransitionName(tvName)) .build(); navController.navigate(R.id.ContactToDetails, arguments, null, extras); 但它没有起作用。 - Antoine El Murr
当我在RecyclerView外尝试时,它可以正常工作,但是在RecyclerView内部它无法工作。 - Antoine El Murr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接