我看了很多关于确定用Glide加载到Android ImageView中的图片大小的帖子,但它们似乎都是指ImageView的大小,或者源图片的原始大小。我需要能够找出ImageView内部的可绘制图像的BOUNDS是什么。
我使用的是Glide 4.11.0和Android系统,目标是API21+。我的布局非常简单。
<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" />
在布局中定义了app:srcCompat值作为样本,在运行时这个ImageView有不同的图片由用户选择显示。这样做的代码也很直接。
GlideApp.with(context)
.load(Uri.parse(path))
.apply(RequestOptions.fitCenterTransform())
.error(R.drawable.ic_image_error)
.into(imageView);
我没有选择指定一个 "硬编码 "的高度宽度,因为这个应用程序可以在许多不同的设备和密度上运行。我指望结合ImageViewGlide来适当地调整图片的大小以适应。
加载和查看都很好--但我需要知道运行这个应用程序的设备屏幕上的实际边界,而不仅仅是可绘制的图像。这是一个类似于 这个问题 从很多年前开始。
我在一个小的测试应用程序中(没有使用Glide),这个工作很好。在那段代码中,我只是使用与布局相关联的图像来进行推导可绘制边界的测试。我一直在做以下工作(在布局完成和ImageView加载图像之后)。
RectF bounds = new RectF();
Drawable drawable = mediaImageView.getDrawable();
mediaImageView.getImageMatrix().mapRect(bounds, new RectF(drawable.getBounds()));
这是一张截图,我们自定义的绘图表面视图的onDraw()方法 经过调整后,覆盖在ImageView上,以绘制它 "认为 "代表可查看图像边界的矩形。
正如你所看到的 mediaImageView.getImageMatrix().mapRect()
方法正确地推导出了矩形,它代表了在ImageView中可见的drawable的边界,如绿色矩形所示。
当我移到使用Glide的 "真正的 "应用程序时,由 "Glide "方法推导出的值是由 mapRect()
的方法不再正确。我怀疑这是因为Glide在掩盖下所做的变换魔法以及它与ImageView的通信方式与上述推导最终可绘制边界的技术有某种程度的冲突。
我还通过调试器检查了当它进入代码时的可绘制边界矩形是什么,在这一关口,在这之前 mapRect()
的调用。在非Glide测试版本中,边界矩形与图像的原始尺寸相匹配(高4032像素,宽3024)。
在Glide版本中,可绘制的直角图的尺寸为 已调 (大概是Glide的)高1332像素,宽2000像素。我猜测这是Glide在暗中做的某种优化。然而,表面上看确实很奇怪,因为这个高度宽度A)绝对不是移动设备上的显示方式(如你在截图中看到的,它比宽高),B)与请求的变换(fitCenterTransform)的比例不匹配。然而,既然它显示正确,那么一定是有其他步骤参与其中,或者此时根本没有引用或使用可绘制的边界数据。
我如何才能获得可绘制的边界(而不仅仅是宽度和高度)?
我找到了一个变通的方法,感谢以下人士 此职位.
关键是在Glide流对drawable进行任何操作之前,但在它从网络中捕获它之后,拦截Glide流,并使用其固有的width-height作为计算变换后的边界的来源。
最后,我修改了用可绘制对象的边界初始化 "DrawView "的代码。这个改变包括以下步骤。
幸运的是,我可以在Glide中使用一个RequestListener,在Glide从URL中抓取尺寸后,但在它执行 "进入 "ImageView之前抓取它。在这个监听器中,我可以执行与我所请求的转换方法相匹配的矩阵操作,以获得正确的边界。然后,我可以调用适当地初始化我们的DrawView自定义视图对象的方法。
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);
剩下的一个问题是,我是否需要担心以这种方式使用匿名监听器?我是否会招致内存泄漏?