问题描述:
一个imageview 控件宽高 640*280 ,通过glide加载要显示的图片,,图片始终显示在imageview 的右边和下边,图片的宽高可能小于或者大于imageview 控件的宽高,如何在imageview 显示图片:如果图片的宽高大于imageview 的宽高可以只显示图片对应的右下部分(此时imageview 宽或者高小于图片的),如果图片的宽高小于imageview 的宽高,可以在imageview 的右边和下边显示图片
讲的很笼统,大概的意思就是imageview空间要显示的图片宽高不是固定的,图片如果小的话,可以完全显示,如果图片比较大的话,imageview会显示部分的图片,当然,此刻imageview的宽或者高可能会填充,显示图片的一部分,那这些的话应该怎么实现呢,先回顾一些imageview的一些知识:
ImageView 的scaleType 分析讲解
ImageView
的 scaleType
属性是 Android 开发中非常关键的一个属性,它决定了图片如何被缩放(或不变)以适应 ImageView
的大小。scaleType
提供了多种模式来应对不同的布局需求。下面是对 ImageView
中 scaleType
属性的详细分析讲解:
1. matrix
- 描述:使用图像矩阵(Image Matrix)来缩放和移动图片。这通常与
setImageMatrix(Matrix matrix)
方法结合使用,以实现复杂的图片变换效果。 - 特点:提供了最大的灵活性,但也需要开发者手动计算矩阵变换。
2. fitXY
- 描述:拉伸图片以完全适应
ImageView
的边界。这可能会导致图片的宽高比失真。 - 特点:简单直接,但可能会破坏图片的原始比例。
3. fitStart
- 描述:保持图片的宽高比,将图片的左上角与
ImageView
的左上角对齐,然后缩放图片以适应ImageView
的宽度或高度(取决于哪个更小)。 - 特点:图片可能会在
ImageView
的底部或右侧留下空白。
4. fitEnd
- 描述:与
fitStart
类似,但将图片的右下角与ImageView
的右下角对齐。 - 特点:同样保持图片的宽高比,但空白区域会出现在
ImageView
的顶部或左侧。
5. fitCenter
- 描述:保持图片的宽高比,将图片缩放以使其完全适应
ImageView
的边界(至少一边相等),然后将图片居中显示。 - 特点:这是最常用的
scaleType
之一,因为它既保持了图片的宽高比,又确保了图片在ImageView
中居中显示。
6. center
- 描述:将图片的中心与
ImageView
的中心对齐,不进行缩放。如果图片的宽高比与ImageView
的宽高比不匹配,图片将不会覆盖整个ImageView
。 - 特点:适用于不需要缩放图片,但需要确保图片中心与
ImageView
中心对齐的场景。
7. centerCrop
- 描述:保持图片的宽高比,但裁剪图片的边界以完全覆盖
ImageView
的边界。这通常意味着图片的某些部分将被裁剪掉。 - 特点:常用于需要图片填满整个
ImageView
,且可以接受部分裁剪的场景,如用户头像或图片轮播。
8. centerInside
- 描述:保持图片的宽高比,将图片缩放以使其完全适应
ImageView
的边界(但不超过ImageView
的边界),然后将图片居中显示。 - 特点:这确保了图片不会超出
ImageView
的边界,但可能会留下空白区域。
总结
ImageView
的 scaleType
属性提供了多种模式来适应不同的布局需求。开发者应根据具体场景选择合适的 scaleType
,以确保图片以最佳方式展示在 ImageView
中。
centerCrop() fitCenter() centerInside() circleCrop() 的区别和使用
在Android开发中,尤其是使用图片加载库(如Glide、Picasso等)时,centerCrop()
, fitCenter()
, centerInside()
, 和 circleCrop()
是常见的变换选项,用于控制图片如何被缩放以适应ImageView的边界。下面我将详细解释每个选项的区别和使用场景。
1. centerCrop()
- 作用:将图片的中心部分裁剪(Crop)到ImageView的边界内,同时保持图片的宽高比。这意呀着图片的某些部分可能会被裁剪掉,以确保图片的整个宽度或高度(取决于图片的宽高比和ImageView的宽高比)都完全填满ImageView。
- 使用场景:当你希望图片充满整个ImageView,且不介意图片的部分内容被裁剪时,这个选项很有用。例如,在展示用户头像或者图片轮播时。
2. fitCenter()
- 作用:将图片按比例缩放,使得图片的宽度或高度(取决于图片的宽高比和ImageView的宽高比)之一等于ImageView的相应尺寸,而另一个尺寸则按比例缩放以保持图片的宽高比。缩放后的图片会居中显示在ImageView中,可能会留下空白边缘。
- 使用场景:当你希望图片保持完整,不希望任何部分被裁剪,但可以接受图片不完全填满ImageView时,这个选项是合适的。例如,在展示产品图片或文章配图时。
3. centerInside()
- 作用:将图片按比例缩放,确保图片的宽度和高度都小于或等于ImageView的相应尺寸,同时保持图片的宽高比。缩放后的图片会居中显示在ImageView中,且图片的边界完全位于ImageView的内部,不会有任何裁剪,但可能会留下较大的空白边缘。
- 使用场景:当你希望图片完全显示在ImageView中,且不希望图片被裁剪或缩放得太大以至于失真时,这个选项是最佳选择。它适用于需要展示清晰、完整图片的场景。
4. circleCrop()
- 作用:将图片裁剪成圆形,并尝试将图片的重要部分(通常是中心部分)保留在圆内。这通常涉及到对图片的缩放和裁剪,以确保整个圆形区域都被图片覆盖,且尽可能保留图片的宽高比。然而,由于裁剪成圆形,图片的某些边缘部分可能会被裁剪掉。
- 使用场景:当你希望展示圆形图片时,如用户头像或某些需要圆形图标的应用场景。这个选项可以确保图片以圆形形式展示,且尽可能保持图片的清晰度和重要内容。
总结
centerCrop()
适用于需要图片填满整个ImageView,且可以接受部分裁剪的场景。fitCenter()
适用于需要图片保持完整,不希望被裁剪,但可以接受不完全填满ImageView的场景。centerInside()
适用于需要图片完全显示在ImageView中,不希望被裁剪或缩放得太大而导致失真的场景。circleCrop()
适用于需要将图片裁剪成圆形展示的场景。
实现方法
要实现你的需求,可以通过以下调整来正确显示图片:
- 确保图片不被放大:避免在
ImageView
中放大图片,应该只在需要时对图片进行裁剪。 - 保持图片的原始比例:只有当图片的尺寸大于
ImageView
时,才进行裁剪操作。
我们可以简化处理,使用 Glide
的 fitCenter
结合 Matrix
来实现这一效果。
代码实现
-
设置
ImageView
的ScaleType
为Matrix
:使用Matrix
进行图像变换,以便精确控制图片的显示位置。 -
使用
Glide
加载图片:加载图片,并确保在ImageView
中进行手动调整。
自定义 ImageView
处理
首先,为了更好地控制图片的位置,我们需要设置 ImageView
的 Matrix
。
val imageView: ImageView = findViewById(R.id.your_image_view)
Glide.with(this)
.asBitmap()
.load("your_image_url")
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
imageView.setImageBitmap(resource)
// 获取图片和 ImageView 的尺寸
val imageWidth = resource.width
val imageHeight = resource.height
val viewWidth = imageView.width
val viewHeight = imageView.height
// 计算比例
val scale = Math.min(viewWidth.toFloat() / imageWidth, viewHeight.toFloat() / imageHeight)
// 创建 Matrix
val matrix = Matrix()
matrix.setScale(scale, scale)
// 移动图片到右下角
val dx = viewWidth - imageWidth * scale
val dy = viewHeight - imageHeight * scale
matrix.postTranslate(dx, dy)
imageView.imageMatrix = matrix
}
override fun onLoadCleared(placeholder: Drawable?) {
// Handle cleanup if needed
}
})
xml 文件
<ImageView
android:id="@+id/your_image_view"
android:layout_width="640dp"
android:layout_height="280dp"
android:scaleType="matrix"
android:background="#CCCCCC"/>
解释
CustomTarget<Bitmap>
: 通过这个Target
,我们可以在图片加载完成后获取到Bitmap
,从而手动调整Matrix
。Matrix
: 使用Matrix
来缩放并移动图片,确保它位于ImageView
的右下角。Scale
: 计算一个合适的缩放比例,确保图片不会被放大,只在需要时进行缩小。
这样设置后,当图片尺寸小于 ImageView
时,图片会保持原比例并显示在右下角;如果图片尺寸大于 ImageView
,则会裁剪并显示图片的右下部分。
但是以上代码并没有达到我的需求,如下修改
调整1:
<FrameLayout
android:layout_width="640dp"
android:layout_height="280dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/iv_guide_doctor"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
android:background="#CCCCCC"
android:layout_gravity="right|bottom"/>
</FrameLayout>
为了实现这个效果,需要对 ImageView
的布局和 Glide
的设置进行一些调整。具体来说,我们将不使用 centerCrop()
,而是通过 Matrix
手动控制图片的显示方式,以确保图片始终位于 ImageView
的右下角并且按照你的要求裁剪。
使用 Glide
加载图片并手动设置 Matrix
val imageView: ImageView = findViewById(R.id.iv_guide_doctor)
Glide.with(mContext)
.asBitmap()
.load(url)
.error(R.mipmap.icon_guide_doctor)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
// 获取图片和 ImageView 的尺寸
val imageWidth = resource.width
val imageHeight = resource.height
val viewWidth = imageView.width
val viewHeight = imageView.height
// 计算比例,确保图片不会被放大
val scale = Math.max(
viewWidth.toFloat() / imageWidth,
viewHeight.toFloat() / imageHeight
)
// 计算平移量,使图片的右下部分显示
val dx = viewWidth - imageWidth * scale
val dy = viewHeight - imageHeight * scale
// 设置图片的 Matrix
val matrix = Matrix()
matrix.setScale(scale, scale)
matrix.postTranslate(dx, dy)
imageView.imageMatrix = matrix
imageView.setImageBitmap(resource)
}
override fun onLoadCleared(placeholder: Drawable?) {
// Handle cleanup if needed
}
})
解释
-
scaleType="matrix"
: 设置ImageView
的scaleType
为matrix
,允许我们手动控制图片的缩放和平移。 -
计算
scale
: 使用Math.max
来计算缩放比例,确保图片在缩放后覆盖整个ImageView
,且不会放大到超出ImageView
尺寸。 -
计算
dx
和dy
: 平移量的计算确保图片的右下部分位于ImageView
的右下角。 -
设置
Matrix
: 最后,使用Matrix
进行缩放和平移操作,确保图片按照你预期的方式显示。
通过这个方法,图片将按照你的要求显示在 ImageView
的右下角,如果图片的高度或宽度大于 ImageView
,只会显示右下部分,而不会显示超出 ImageView
的部分。
这个方法可以尝试,但涉及到矩阵和大小的关系,算上去可能比较麻烦,这边还有一个最简单粗暴的方法,直接在onResourceReady 的方法中,动态设置一下imageview的宽高为获取到的图片的宽高,然后直接显示图片。这样可以确保图片以其原始尺寸显示在 ImageView
中,而无需进行缩放或裁剪。以下是如何实现这个功能的代码示例。
修改后的 Java 代码
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView = findViewById(R.id.iv_guide_doctor);
String url = "your_image_url"; // Replace with your image URL
Glide.with(this)
.asBitmap()
.load(url)
.error(R.mipmap.icon_guide_doctor)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
// Get the dimensions of the loaded bitmap
int imageWidth = resource.getWidth();
int imageHeight = resource.getHeight();
// Set the ImageView's layout parameters to match the image dimensions
ViewGroup.LayoutParams params = imageView.getLayoutParams();
params.width = imageWidth;
params.height = imageHeight;
imageView.setLayoutParams(params);
// Set the ImageView's image to the loaded bitmap
imageView.setImageBitmap(resource);
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
// Handle cleanup if needed
}
});
}
}
<FrameLayout
android:layout_width="@dimen/px640"
android:layout_height="@dimen/px280"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/iv_guide_doctor"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitEnd"
android:layout_gravity="right|bottom"
/>
</FrameLayout>
解释
-
onResourceReady
方法中动态设置ImageView
的宽高:- 使用
Bitmap
对象的getWidth()
和getHeight()
方法来获取加载的图片的实际宽高。 - 通过获取
ImageView
的LayoutParams
,然后设置宽高为图片的宽高。 - 最后,调用
setLayoutParams
方法将更新后的布局参数应用到ImageView
上。
- 使用
-
直接显示图片:
- 设置
ImageView
的宽高之后,使用setImageBitmap(resource)
方法将图片直接显示在ImageView
中。
- 设置
结果
这样做的结果是:
ImageView
将会动态调整它的宽高,以适应加载的图片的实际尺寸。- 图片将以原始大小显示在
ImageView
中,不会进行缩放或裁剪。 ImageView
将自动调整并显示在FrameLayout
的右下角(因为你设置了layout_gravity="right|bottom"
)。
通过这种方法,你可以确保图片始终以其原始尺寸显示,并且 ImageView
也会根据图片的尺寸进行调整。