确定动画后 ImageView 共享元素的最终大小

Determine final size of ImageView shared element after animation

我有一些共享元素,我正在通过 ActivityOptions.makeSceneTransitionAnimation 在两个活动之间进行转换。当我输入第二个 activity 时,我想确定 ImageView 的最终目标大小,以便我可以设置 ImageView 的适当宽度。我相信这样做会让它右边的对象(也是共享元素)平滑过渡。

ImageView 是具有固定高度和 wrap_content 宽度的 fitStart scaleType。图像将被动态加载并从第一个 activity 缩小到第二个,所以我不知道最终宽度。在过渡开始之前,我想设置 ImageViewLayoutParams 宽度以匹配过渡结束后的最终宽度。

目前,这个 ImageViewwrap_content 属性 导致它右边的元素不知道它最终的归宿在哪里,所以它离开了在返回并降落在正确的位置之前向右移动屏幕。

这是动画的 gif。第一个元素是 ImageView,动画正确,第二个元素是 ImageView 右边的按钮:

请注意,当第二个 activity 返回到第一个 activity 时,第二个元素平滑地过渡回屏幕左侧,因为结束位置已知。

当我给 ImageView 一个特定的宽度,例如 100dp 而不是 wrap_content(然后在转换完成后将其改回 wrap_content),第二个元素更平滑地移动到它的最终静止位置,但由于 ImageView 将被动态加载和缩放,我不会事先知道 XML 中图像的真实宽度,所以总会有一个不稳定的运动当我在过渡后将其更改为 wrap_content 时,第二个元素的。

所以我想确定 ImageView 的目标宽度,并在第二个 activity 开始转换之前以编程方式设置它,以便第二个元素知道它需要向左移动多远走。我试过 ViewTreeObserverTransitionValues 但我不知道如何获得 ImageView 过渡到的最终宽度。

我可以在第二个 activity 的 onCreate 中调用什么来确定 ImageView 在转换后最终的宽度吗?


编辑

我尝试了 中的解决方案,但它报告的是 ImageView 的起始宽度,而不是它过渡到的最终宽度。作为参考,这些是我正在切换的两个活动的布局:

请注意,我正在移动和缩小 ImageView。

我调整了答案的代码,因为我没有使用支持库并且不得不在 onPreDraw() 调用中移动到 imageView.getViewTreeObserver() 以避免 IllegalStateException

postponeEnterTransition();

final ImageView imageView = (ImageView) findViewById(R.id.image_view);
final ViewGroup.LayoutParams imageViewLayoutParams = imageView.getLayoutParams();
final ViewTreeObserver viewTreeObserver = imageView.getViewTreeObserver();

viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
  @Override public boolean onPreDraw() {
    imageView.getViewTreeObserver().removeOnPreDrawListener(this);

    // You can acquire the width here
    logoLayoutParams.width = imageView.getWidth();
    Log.i(TAG, "width is " + imageViewLayoutParams.width);
    imageView.setLayoutParams(imageViewLayoutParams);
    // `imageView` has been laid out, but not yet been drawn
    startPostponedEnterTransition();
    return true;
  }
});

日志报告宽度为 998,这是 Activity1 中 imageView 的较大尺寸(过渡前的起始尺寸)。所以第二部还在飞出屏幕

现在我有了这段代码,我可以使用大图的纵横比信息来计算小图的最终宽度,因为我知道最终高度,但是fitStart scaleType?

如果 Android 能告诉我共享元素定位的最终大小,那就太好了。

情况如下:如果您在第二个 activity 中将资源从 @drawable/first_element 更改为 @drawable/first_element_thumb,您将不会再遇到这种行为。不利的一面是,每次开始转换时您都会看到一个故障,这是因为在转换开始之前可绘制对象正在从高分辨率更改为低分辨率。

这是 300 毫秒的动画时间:

这是 5000 毫秒的动画时间:

如果您希望过渡没有这种故障,那么解决方案是从高分辨率可绘制对象开始过渡,并在过渡视图时将该可绘制对象替换为低分辨率。可以看到Nick Butcher describing the feature in his "Animatable" talk. You'll end up writing your custom transition class like this one.