如何使用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一起工作,但是有一些事情要记住:
-
不要尝试在你的Fragment的
onCreateView
中设置sharedElementsTransition
。 在创buildFragment实例或onCreate
时,必须定义它们。 -
记下有关进入/退出转换和sharedElementTransitionanimation的官方文档。 他们不一样。
-
试错:)
这应该是对已接受答案的评论,因为我无法对此发表评论。
被接受的答案(由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));
以下是一些有用的资源:
关键是使用自定义事务
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" />
在DetailFragment
的onCreateView()
方法中,我们必须决定应该显示哪个图像资源(如果不这样做,共享元素将在转换后消失)。
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()); } }