【问题标题】:Shared Element with scaleType centerCrop transition is jumpy具有 scaleType centerCrop 过渡的共享元素跳跃
【发布时间】:2016-10-24 00:52:23
【问题描述】:

当 2 ImageViews 从一个屏幕转到下一个屏幕时,我正在尝试实现共享元素转换。其中一张图像在两个屏幕上的 scaleType 均为 centerCrop。我面临的问题是,当过渡开始时,图像将在动画到下一个屏幕之前变为原始大小(裁剪之前)。当它到达下一个屏幕时,它会以其原始大小到达它,然后才将其裁剪到目标图像视图。

整个体验并不流畅,而且真的让人眼花缭乱。 我使用的代码是:

public void animateIntent(View view, ArticleCoverData articleCoverData) {
    Intent intent = new Intent(mActivity, ReaderActivity.class);
    intent.putExtra(Constants.ARTICLE_DATA, articleCoverData);

    // The view animation will start from
    View coverStartView = view.findViewById(R.id.coverImage);
    View coverDiagonalDecoratorStartView = view.findViewById(R.id.diagonal_image_decorator);

    Pair<View, String> pair1 = Pair.create(coverStartView, mActivity.getString(R.string.transition_timeline_cover_image_to_reader_name));
    Pair<View, String> pair2 = Pair.create(coverDiagonalDecoratorStartView, mActivity.getString(R.string.transition_timeline_cover_image_diagonal_decorator_to_reader_name));

    ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(mActivity, pair1, pair2);
    ActivityCompat.startActivity(mActivity, intent, options.toBundle());
}

图片是使用Glide从网上加载的,代码如下:

Glide.with(mActivity).load(articleCoverData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).dontTransform().into(holder.coverImage);

在接收端,图像加载如下:

Glide.with(mContext).load(mData.mImageUrl).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(mCoverImageView);

按照我定义的样式:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Add this line -->
    <item name="android:windowContentTransitions">true</item>

    <!-- This is the color of the Status bar -->
    <item name="colorPrimaryDark">@color/transparent</item>

    <!-- specify shared element transitions -->
    <item name="android:windowSharedElementEnterTransition">
        @transition/change_image_transform</item>
    <item name="android:windowSharedElementExitTransition">
        @transition/change_image_transform</item>
</style>

change_image_transform 是:

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

编辑:尝试将过渡更改为:

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

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

但结果是一样的。

问题是:我在这里遗漏了什么吗?我还需要做些什么来让这段经历变得平淡无奇吗?或者这是一个 Android 错误?

【问题讨论】:

    标签: android crop android-transitions android-glide shared-element-transition


    【解决方案1】:

    最后,设法解决了这个问题。使用以下代码和配置实现了预期的结果:

    private static void startAnimatedTransitionIntent(Activity context, View view, ArticleCoverData articleCoverData) {
        Intent intent = new Intent(context, ReaderActivity.class);
        intent.putExtra(Constants.ARTICLE_DATA, articleCoverData);
    
        View coverStartView = view.findViewById(R.id.coverImage);
        View coverDiagonalDecoratorStartView = view.findViewById(R.id.diagonal_image_decorator);
    
        Window window = context.getWindow();
        View decor = window.getDecorView();
        View navigationBarStartView = decor.findViewById(android.R.id.navigationBarBackground);
    
        List<Pair<View, String>> pairs = new ArrayList<>();
        pairs.add(Pair.create(coverStartView, context.getString(R.string.transition_timeline_cover_image_to_reader_name)));
        pairs.add(Pair.create(coverDiagonalDecoratorStartView, context.getString(R.string.transition_timeline_cover_image_diagonal_decorator_to_reader_name)));
    
        if (navigationBarStartView != null) {
            pairs.add(Pair.create(navigationBarStartView, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));
        }
    
        ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(context, pairs.toArray(new Pair[pairs.size()]));
        ActivityCompat.startActivity(context, intent, options.toBundle());
    }
    

    我正在使用 Picasso 和以下代码将图像加载到图像视图中:

    Picasso.with(mActivity).load(articleCoverData.mImageUrl).into(articleVH.coverImage);
    

    在接收端,我以相同的方式应用图像:

    Picasso.with(mContext).load(mData.mImageUrl).into(mCoverImageView);
    

    风格:

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:statusBarColor">@color/app_red</item>
        <item name="android:windowContentTransitions">true</item>
    
        <!-- This is the color of the Status bar -->
        <item name="colorPrimaryDark">@color/transparent</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    
        <!--<item name="android:windowEnterTransition">@transition/cheeses_enter</item>-->
        <!--<item name="android:windowExitTransition">@transition/cheeses_exit</item>-->
    
        <item name="android:windowSharedElementEnterTransition">@transition/cheeses_enter</item>
        <item name="android:windowSharedElementExitTransition">@transition/cheeses_exit</item>
    </style>
    

    两个转换:cheeses_entercheeses_exit 是:

    <?xml version="1.0" encoding="utf-8"?>
    <transitionSet>
        <changeBounds />
        <changeTransform />
        <changeClipBounds />
        <changeImageTransform />
    </transitionSet>
    

    重要的是使用 ImageView scaleType 参数应用您的缩放类型,而不是使用 Picasso 裁剪或 Glide 裁剪。

    因为如果您这样做,裁剪和取消裁剪操作将作为过渡的一部分执行。

    【讨论】:

    • 这是关键“重要的是使用 ImageView scaleType 参数应用您的比例类型,而不是使用 Picasso 裁剪或 Glide 裁剪。”谢谢
    • 在我的情况下,启动活动具有 CenterCrop 属性,并且在打开其平滑但在返回动画时,它会导致问题。第一个动画缩小到单元格的高度,然后填充宽度。
    • 我应该做些什么改变?由于开口很好,返回时缩放不匹配。
    • @UsmanRana,我遇到了与 centerCrop 相同的问题。你找到解决办法了吗。请分享
    • @mukesh 默认转换将允许您在打开或关闭时在 1 个位置遭受混蛋(如果您在 onTransitionStart 方法中更改 scaleType)。可以解决这个问题的想法是不使用 centerCrop,而是通过设置 scaleType 在视图上应用缩放。
    【解决方案2】:

    我面临同样的问题,我已经在我的Glide 加载请求中使用了dontAnimate() + dontTransform()

    对我来说,我的解决方案是删除

    clipToPadding="false"
    clipChildren="false"
    

    来自我的 ImageView 的容器 ViewGroup。

    在共享元素转换期间使用scaleType="centerCrop" 时,这些属性使我的图像未剪辑。

    【讨论】:

      【解决方案3】:

      只是为了给遇到这个问题的人一个答案(以及更多解释)。

      首先,只需使用&lt;changeImageTransform/&gt;&lt;changeBounds/&gt; 就足以进行转换。

      问题主要在于 Glide 如何处理图像视图/drawable 的测量。有一些延迟,因此没有创建过渡动画。

      Picasso 基于scaletype 提供足够快的图像(矩阵)位置值,并且过渡工作。

      【讨论】:

        【解决方案4】:

        在你的change_image_transform.xml中,改成这个

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

        【讨论】:

        • 我看到您将图像 url 传递给新活动,然后在新活动中,您使用 glide 再次加载它?尝试传递图像的位图,我认为它会更平滑
        • 是的,但是图片是glide缓存的,所以第二次使用时是从磁盘使用的,不再从web加载。
        猜你喜欢
        • 1970-01-01
        • 2016-04-23
        • 1970-01-01
        • 1970-01-01
        • 2020-01-17
        • 1970-01-01
        • 2016-02-04
        • 2020-04-29
        • 1970-01-01
        相关资源
        最近更新 更多