简体   繁体   中英

How can I determine the final bounds of a drawable loaded by Glide into an ImageView

I have reviewed many posts about determining size of images loaded with Glide into an Android ImageView, but they all seem to either refer to the ImageView size, or the original size of the source image. I need to be able to find out what the resulting BOUNDS is of the drawable INSIDE the ImageView.

I am using Glide 4.11.0 with Android targeting API21+. My layout is quite simple:

        <ImageView
            android:id="@+id/media_image_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            app:srcCompat="@drawable/grandparents_grandchildren_translucent" />

The app:srcCompat value is defined in the layout as a sample, at runtime this ImageView has different images chosen by the user to display. The code to do this is also straight-forward:

            GlideApp.with(context)
                    .load(Uri.parse(path))
                    .apply(RequestOptions.fitCenterTransform())
                    .error(R.drawable.ic_image_error)
                    .into(imageView);

I don't have the option to specify a "hard-coded" height/width, as this app runs on many different devices and densities. I am counting on the combination of the ImageView/Glide to size the image appropriately to fit.

Loading and viewing all works fine - but I need to know the actual bounds in pixels on the screen of the device running this app of just the drawable. It is a similar ask to this question from many years ago.

I had this working fine in a small test app (not using Glide). In that code, I just used the image associated with the layout to do my testing of deriving the drawable bounds. I had been doing the following (after layout was complete and the ImageView loaded the image):

 RectF bounds = new RectF();
 Drawable drawable = mediaImageView.getDrawable();
 mediaImageView.getImageMatrix().mapRect(bounds, new RectF(drawable.getBounds()));

Here is a screenshot, with the onDraw() method of our custom drawing surface view which overlays the ImageView adjusted to paint the rectangle it "thinks" represents the bounds of the viewable image:

在此处输入图像描述

As you can see the mediaImageView.getImageMatrix().mapRect() method has properly derived the rectangle which represents the bounds of the drawable as visible within the ImageView, as shown by the green rectangle.

When I moved over to the "real" app which uses Glide, the value derived by the mapRect() approach is no longer correct. I suspect that this is because the transform magic that Glide does under the covers and how it communicates with the ImageView are somehow at odds with the above technique for deriving the bounds of the final drawable:

在此处输入图像描述

I have also checked via the debugger what the drawable bounds rect is when it comes into the code at this juncture PRIOR to the mapRect() call. In the non-Glide test version the bounds rect matches the original size of the image (4032 pixels high by 3024 wide).

In the Glide version the drawable rect has already been adjusted (presumably by Glide) to be 1332 pixels high and 2000 pixels wide. I presume this is some sort of optimization thing that Glide is doing under the covers. However it does seem odd on the surface because that height/width is A) definitely not how it shows on the mobile device (it is taller than it is wide, as you can see in the screenshot), and B) doesn't match scale wise with the requested transform (fitCenterTransform). However, since it is displaying correctly there must either be some other step involved, or the drawable bounds data is simply not being referenced or used at this point.

How can I get the BOUNDS (not just width/height) of the drawable as viewed?

I have found a work-around thanks to this post .

The key is to intercept the Glide flow prior to it doing any operations on the drawable, but after it has snagged it from the network, and using its intrinsic width/height as the source for calculating the bounds as transformed.

I ended up changing the code that initializes our "DrawView" with the bounds of the drawable. The change involved these steps:

  1. Get the correct width/height of the drawable prior to Glide doing any transformations.
  2. Calculate the drawable bounds manually using a matrix conversion that takes into account the width/height of the ImageView and its scale type (ours is always FitCenter, so the code used is fixed to using that).
  3. Use the resulting bounds to initialize our custom "drawView" view.

Fortunately, I can use a RequestListener within Glide to snag the size after Glide grabs it from the URL but before it performs the "into" the ImageView. Within this listener I can perform the matrix operations that match the transformation approach I have requested in order to get the correct bounds. Then I can call the method that initializes our DrawView custom view object appropriately:

       GlideApp.with(this)
                .load(Uri.parse(currentMedia.getUriPathToMedia()))
                .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) {
                        RectF visualizedDrawableRect = new RectF(); // left, top, right, bottom
                        Matrix m = new Matrix();
                        RectF srcDrawableRect = new RectF(0, 0, resource.getIntrinsicWidth(), resource.getIntrinsicHeight());
                        RectF imageViewRect = new RectF(0, 0, mediaImageView.getWidth(), mediaImageView.getHeight());
                        if ( m.setRectToRect(srcDrawableRect, imageViewRect, Matrix.ScaleToFit.CENTER) ) {
                            m.mapRect(visualizedDrawableRect,srcDrawableRect);

                            // INITIALIZE OUR DRAWVIEW HERE
                            initializeDrawView(visualizedDrawableRect);
                        }
                        return false;
                    }
                })
                .apply(RequestOptions.fitCenterTransform())
                .error(R.drawable.ic_image_error)
                .into(mediaImageView);

One remaining question is whether I have to be concerned about using an anonymous listener in this way? Am I incurring a memory leak?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM