Android Glide library not working with shared element transitions

9.1k views Asked by At

I'm looking to adopt the Glide library in place of Universal Image Loader but I'm running into a problem with regards to shared element transitions.

In my simple Sandbox I've created the following transition using UIL: https://dl.dropboxusercontent.com/u/97787025/device-2015-06-18-113333.mp4

Pretty simple, and it works fine. But when I used Glide, it doesn't look so nice: https://dl.dropboxusercontent.com/u/97787025/device-2015-06-18-114508.mp4

Here is the code I'm using

The first activity:

public class MainActivity extends BaseActivity {

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.main);

        final ImageView iv = (ImageView) findViewById(R.id.main_image);

        displayImageGlide(BaseActivity.IMAGE_URL, iv, true);

        Button button = (Button) findViewById(R.id.main_button);
        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(), DifferentActivity.class);
                startActivity(intent, iv);
            }

        });
    }

}

And the second:

public class DifferentActivity extends BaseActivity {

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        setContentView(R.layout.different);

        ImageView imageView = (ImageView) findViewById(R.id.diff_image);

        displayImageGlide(BaseActivity.IMAGE_URL, imageView, false);
    }

}

BaseActivity just contains displayImageGlide

public void displayImageGlide(String url, ImageView imageView) {
    Glide.with(this).load(url)
            .asBitmap().transform(new CustomTransformation(this))
            .skipMemoryCache(true)
            .diskCacheStrategy(DiskCacheStrategy.SOURCE)
            .into(imageView);
}

private static class CustomTransformation extends BitmapTransformation {

    public CustomTransformation(Context context) {
        super(context);
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return bitmapChanger(toTransform, outWidth, outHeight);
    }

    @Override
    public String getId() {
        return "some_id_1";
    }

}

private static Bitmap bitmapChanger(Bitmap bitmap, int desiredWidth, int desiredHeight) {
    float originalWidth = bitmap.getWidth();
    float originalHeight = bitmap.getHeight();

    float scaleX = desiredWidth / originalWidth;
    float scaleY = desiredHeight / originalHeight;

    //Use the larger of the two scales to maintain aspect ratio
    float scale = Math.max(scaleX, scaleY);

    Matrix matrix = new Matrix();

    matrix.setScale(scale, scale);

    //If the scaleY is greater, we need to center the image
    if(scaleX < scaleY) {
        float tx = (scale * originalWidth - desiredWidth) / 2f;
        matrix.postTranslate(-tx, 0f);
    }

    Bitmap result = Bitmap.createBitmap(desiredWidth, desiredHeight, bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(result);
    canvas.drawBitmap(bitmap, matrix, new Paint());
    return result;
}

I've tried removing the cache lines from the Glide builder (used to prevent it from caching what I'm trying to tweak) but that didn't help. Would love to adopt Glide, but it's kind of a deal breaker if this won't work. If anyone has some input I'd appreciate it, thanks!

2

There are 2 answers

3
Rodrigo Direito On

I tried your code and got the same result, then I tried another implementation following this: https://github.com/codepath/android_guides/wiki/Shared-Element-Activity-Transition

And made some changes, which I think are the key here:

The centerCrop should be set on the ImageView, if we set it with Glide it causes the same bug. activity_main.xml

    <ImageView
      android:id="@+id/ImageView"
      android:layout_width="match_parent"
      android:layout_height="150dp"
      android:layout_centerInParent="true"
      android:transitionName="detail_image"
      android:scaleType="centerCrop"
    />

BaseActivity.java On the MainActivity dontTransform should be true and on DifferentActivity false.

    public void displayImageGlide(String url, ImageView imageView, Boolean dontTransform) {
    if (dontTransform) {
        Glide.with(this).load(url)
                .skipMemoryCache(true)
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .dontTransform()
                .into(imageView);
        return;
    }

        Glide.with(this).load(url)
                .skipMemoryCache(true)
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .into(imageView);
   }

Edit, see how it looks: https://www.dropbox.com/s/30s5l8awxogltls/device-2015-06-23-153153.mp4?dl=0

1
Seven On

For those of you that are struggling with the SharedElementTransition using Glide I think I got a workaround that works, or at least it worked for me. In your second activity or fragment use this code:

postponeEnterTransition();
GlideApp.with(this)
        .load(imageToLoad)
        .listener(new RequestListener<Drawable>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                startPostponedEnterTransition();
                return false;
            }
        })
        .into(imageView);

If you are targeting API<21 use:

supportPostponeEnterTransition();
supportStartPostponedEnterTransition();

Hope that helps!