A
B
ImageView
ViewPager
RecyclerView
GridFragment
ImageData
ImagePagerFragment
onClick
ImageFragments
MainActivity
transitionName
ImageFragment
setTransitionName
onCreateView
SharedElementCallbacks
onMapSharedElements
FragmentManager
fragment.getFragmentManager() .beginTransaction() .setReorderingAllowed(true) // setAllowOptimization before 26.1.0 .addSharedElement(imageView, imageView.getTransitionName()) .replace(R.id.fragment_container, new ImagePagerFragment(), ImagePagerFragment.class.getSimpleName()) .addToBackStack(null) .commit();
setReorderingAllowed
true
onDestroy()
onCreate(Bundle)
TransitionSet
<ImagePagerFragment.java>
Transition transition = TransitionInflater.from(getContext()) .inflateTransition(R.transition.image_shared_element_transition); setSharedElementEnterTransition(transition);
<image_shared_element_transition.xml>
<?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:duration="375" android:interpolator="@android:interpolator/fast_out_slow_in" android:transitionOrdering="together"> <changeClipBounds/> <changeTransform/> <changeBounds/> </transitionSet>
SharedElementCallback
setExitSharedElementCallback()
Fragment
<GridFragment.java>
setExitSharedElementCallback( new SharedElementCallback() { @Override public void onMapSharedElements( List<String> names, Map<String, View> sharedElements) { // Locate the ViewHolder for the clicked position. RecyclerView.ViewHolder selectedViewHolder = recyclerView .findViewHolderForAdapterPosition(MainActivity.currentPosition); if (selectedViewHolder == null || selectedViewHolder.itemView == null) { return; } // Map the first shared element name to the child ImageView. sharedElements .put(names.get(0), selectedViewHolder.itemView.findViewById(R.id.card_image)); } });
setEnterSharedElementCallback()
setEnterSharedElementCallback( new SharedElementCallback() { @Override public void onMapSharedElements( List<String> names, Map<String, View> sharedElements) { // Locate the image view at the primary fragment (the ImageFragment // that is currently visible). To locate the fragment, call // instantiateItem with the selection position. // At this stage, the method will simply return the fragment at the // position and will not create a new one. Fragment currentFragment = (Fragment) viewPager.getAdapter() .instantiateItem(viewPager, MainActivity.currentPosition); View view = currentFragment.getView(); if (view == null) { return; } // Map the first shared element name to the child ImageView. sharedElements.put(names.get(0), view.findViewById(R.id.image)); } });
onCreateView()
postponeEnterTransition()
startPostponedEnterTransition()
postponeEnterTransition
startPostponeEnterTransition
<ImageFragment.java>
Glide.with(this) .load(arguments.getInt(KEY_IMAGE_RES)) // Load the image resource .listener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { getParentFragment().startPostponedEnterTransition(); return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { getParentFragment().startPostponedEnterTransition(); return false; } }) .into((ImageView) view.findViewById(R.id.image));
setExitTransition(TransitionInflater.from(getContext()) .inflateTransition(R.transition.grid_exit_transition));
<grid_exit_transition.xml>
<?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:duration="375" android:interpolator="@android:interpolator/fast_out_slow_in" android:startDelay="25"> <fade> <targets android:targetId="@id/card_view"/> </fade> </transitionSet>
GridAdapter
// The 'view' is the card view that was clicked to initiate the transition. ((TransitionSet) fragment.getExitTransition()).excludeTarget(view, true);
onViewCreated
recyclerView.addOnLayoutChangeListener( new OnLayoutChangeListener() { @Override public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { recyclerView.removeOnLayoutChangeListener(this); final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); View viewAtPosition = layoutManager.findViewByPosition(MainActivity.currentPosition); // Scroll to position if the view for the current position is null (not // currently part of layout manager children), or it's not completely // visible. if (viewAtPosition == null || layoutManager.isViewPartiallyVisible(viewAtPosition, false, true)){ recyclerView.post(() -> layoutManager.scrollToPosition(MainActivity.currentPosition)); } } });