如何使用Fragments启动共享元素转换?

我试图在新材料devise规范中描述的具有“共享元素”的片段之间实现转换。 我唯一可以find的方法是ActivityOptionsCompat.makeSceneTransitionAnimation ,我相信它只适用于Activity。 我一直在寻找这个相同的function,但/碎片。

我有同样的问题,但通过添加另一个片段的新片段工作。 下面的链接对开始这个很有帮助: https : //developer.android.com/training/material/animations.html#Transitions

以下是我的代码工作。 我将一个ImageView从一个片段移动到另一个片段。 确保您想要animation的View在两个片段中都具有相同的android:transitionName 。 其他内容并不重要。

作为一个testing,你可以把它复制到你的布局xml文件。 确保图像存在。

 <ImageView android:transitionName="MyTransition" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/test_image" /> 

然后我的res/transition文件夹中有一个名为change_image_transform.xml的文件。

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

现在你可以开始了。 让我们说你有片段A包含图像,并希望添加片段B.

运行在片段A:

 @Override public void onClick(View v) { switch(v.getId()) { case R.id.product_detail_image_click_area: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform)); setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode)); // Create new fragment to add (Fragment B) Fragment fragment = new ImageFragment(); fragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform)); fragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode)); // Our shared element (in Fragment A) mProductImage = (ImageView) mLayout.findViewById(R.id.product_detail_image); // Add Fragment B FragmentTransaction ft = getFragmentManager().beginTransaction() .replace(R.id.container, fragment) .addToBackStack("transaction") .addSharedElement(mProductImage, "MyTransition"); ft.commit(); } else { // Code to run on older devices } break; } } 

我张贴这个答案,因为我在这里是新的,无法发表评论。

只要源视图和目标视图具有相同(和唯一)的transitionName,共享元素片段转换可以与ListView一起工作。

如果你让列表视图适配器为你想要的视图设置唯一的transitionNames(例如一些常量+特定的项目ID) ,并且改变你的细节片段以在运行时(onCreateView)设置相同的transitionNames到目标视图, !

共享元素可以和Fragments一起工作,但是有一些事情要记住:

  1. 不要尝试在你的Fragment的onCreateView中设置sharedElementsTransition 。 在创buildFragment实例或onCreate时,必须定义它们。

  2. 记下有关进入/退出转换和sharedElementTransitionanimation的官方文档。 他们不一样。

  3. 试错:)

这应该是对已接受答案的评论,因为我无法对此发表评论。

被接受的答案(由WindsurferOak和ar34z)起作用,除了导致backStack导航的空指针exception的“小问题”。 看来应该在目标片段上而不是原始片段上调用setSharedElementReturnTransition()

所以,而不是:

 setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform)); 

它应该是

 fragment.setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform)); 

https://github.com/tevjef/Rutgers-Course-Tracker/issues/8

关键是使用自定义事务

 transaction.addSharedElement(sharedElement, "sharedImage"); 

两个片段之间的共享元素转换

在这个例子中,两个不同的ImageViews应该从ChooserFragment转换到DetailFragment

ChooserFragment布局中,我们需要唯一的transitionName属性:

 <ImageView android:id="@+id/image_first" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_first" android:transitionName="fistImage" /> <ImageView android:id="@+id/image_second" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_second" android:transitionName="secondImage" /> 

ChooserFragments类中,我们需要将被单击的View和一个ID传递给父Activity以处理碎片的replace(我们需要该ID来知道在DetailFragment显示哪个图像资源)。 如何将信息传递给父母的详细信息肯定会在另一个文档中介绍。

 view.findViewById(R.id.image_first).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mCallback != null) { mCallback.showDetailFragment(view, 1); } } }); view.findViewById(R.id.image_second).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mCallback != null) { mCallback.showDetailFragment(view, 2); } } }); 

DetailFragment ,共享元素的ImageView也需要唯一的transitionName属性。

 <ImageView android:id="@+id/image_shared" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:transitionName="sharedImage" /> 

DetailFragmentonCreateView()方法中,我们必须决定应该显示哪个图像资源(如果不这样做,共享元素将在转换后消失)。

 public static DetailFragment newInstance(Bundle args) { DetailFragment fragment = new DetailFragment(); fragment.setArguments(args); return fragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View view = inflater.inflate(R.layout.fragment_detail, container, false); ImageView sharedImage = (ImageView) view.findViewById(R.id.image_shared); // Check which resource should be shown. int type = getArguments().getInt("type"); // Show image based on the type. switch (type) { case 1: sharedImage.setBackgroundResource(R.drawable.ic_first); break; case 2: sharedImage.setBackgroundResource(R.drawable.ic_second); break; } return view; } 

Activity正在接收callback并处理碎片的replace。

 @Override public void showDetailFragment(View sharedElement, int type) { // Get the chooser fragment, which is shown in the moment. Fragment chooserFragment = getFragmentManager().findFragmentById(R.id.fragment_container); // Set up the DetailFragment and put the type as argument. Bundle args = new Bundle(); args.putInt("type", type); Fragment fragment = DetailFragment.newInstance(args); // Set up the transaction. FragmentTransaction transaction = getFragmentManager().beginTransaction(); // Define the shared element transition. fragment.setSharedElementEnterTransition(new DetailsTransition()); fragment.setSharedElementReturnTransition(new DetailsTransition()); // The rest of the views are just fading in/out. fragment.setEnterTransition(new Fade()); chooserFragment.setExitTransition(new Fade()); // Now use the image's view and the target transitionName to define the shared element. transaction.addSharedElement(sharedElement, "sharedImage"); // Replace the fragment. transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName()); // Enable back navigation with shared element transitions. transaction.addToBackStack(fragment.getClass().getSimpleName()); // Finally press play. transaction.commit(); } 

不要忘记 – Transition本身。 本示例移动并缩放共享元素。

 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class DetailsTransition extends TransitionSet { public DetailsTransition() { setOrdering(ORDERING_TOGETHER); addTransition(new ChangeBounds()). addTransition(new ChangeTransform()). addTransition(new ChangeImageTransform()); } }