我决定让共享元素过渡在2窗格模式下的两个片段之间工作的最简单方法是自己制作动画。 在我的解决方案中,我不将细节片段替换为所选网格图像的细节。 相反,我只是使用来自选定网格项的新数据刷新布局控件。 为了防止在将目标ImageView临时从局部视图中移出并放置在叠加层中(用于动画)时调整父线性布局的大小,必须强制ImageView父对象调整为包含子对象的大小,然后在之后将其恢复为原始布局的宽度和高度动画。 这是响应网格项单击事件执行动画的功能:
/**
* Sets up and runs an animation that translates and scales the
* selected poster in the grid view to the poster ImageView in the
* detail fragment.
* @param srcView
* @param destView
*/
private void runAnimation(final ImageView srcView, final ImageView destView) {
final ViewGroup destParentView = (ViewGroup)destView.getParent();
// Set the destination image view's parent (FrameLayout) to
// keep the width and height of image view that will be
// temporarily re-parented during the animation. This will
// ensure that the enclosing LinearLayout will remain fixed
// in appearance during the animation.
final int parentLayoutWidth = destParentView.getLayoutParams().width;
final int parentLayoutHeight = destParentView.getLayoutParams().height;
destParentView.getLayoutParams().width = destParentView.getMeasuredWidth();
destParentView.getLayoutParams().height = destParentView.getMeasuredHeight();
// Scale the destination image to the size of
// the source image. The animation will restore
// the destination image scale when it is run.
// Note that the scale needs to be set before any
// translation so that the translation takes into
// account the change in scale.
float scaleX = (float)destView.getMeasuredWidth()
/ (float)srcView.getMeasuredWidth();
float scaleY = (float) destView.getMeasuredHeight()
/ (float) srcView.getMeasuredHeight();
destView.setScaleX(1f / scaleX);
destView.setScaleY(1f / scaleY);
// Now set translation on scaled image so that the
// destination image begins at the same position as
// the source image. The destination image translation
// will be returned to 0 during the animation.
int[] srcLocation = {0, 0};
int[] dstLocation = {0, 0};
srcView.getLocationOnScreen(srcLocation);
destView.getLocationOnScreen(dstLocation);
destView.setTranslationX(srcLocation[0] - dstLocation[0]);
destView.setTranslationY(srcLocation[1] - dstLocation[1]);
// The overlay must be created from any view whose bounds
// encompasses both the source and destination views.
final ViewGroup rootView =
(ViewGroup)MainActivity.this.findViewById(R.id.main_content);
rootView.getOverlay().add(destView);
// Run animation and when it completes, move the destination
// view from the overlay back to it's original parent. Also,
// restore the parent's layout params which were changed to
// act as a placeholder with the image was being animated.
destView.animate()
.scaleX(1f)
.scaleY(1f)
.translationX(0)
.translationY(0)
.setInterpolator(new DecelerateInterpolator(2))
.setDuration(500)
.withEndAction(new Runnable() {
@Override
public void run() {
rootView.getOverlay().remove(destView);
destParentView.getLayoutParams().width = parentLayoutWidth;
destParentView.getLayoutParams().height = parentLayoutHeight;
destParentView.addView(destView);
}
});
}