Android: 缩放可绘制或背景图像?

在布局上,我想缩放背景图像(保持它的长宽比)到页面创建时分配的空间。有人知道怎么做吗?

我正在使用 layout.setBackgroundDrawable()BitmapDrawable()来设置 gravity进行裁剪和填充,但是没有看到任何缩放选项。

299821 次浏览

在使用它作为背景之前,你必须预先缩放这个可绘制的东西

还没有尝试做你想做的事情,但是你可以使用 android:scaleType="fitXY"来缩放一个 ImageView
它的大小将适合任何大小,你给的图像视图。

所以你可以为你的布局创建一个 FrameLayout,把 ImageView 放在里面,然后在 FrameLayout 中你需要的任何其他内容以及透明的背景。

<FrameLayout
android:layout_width="fill_parent" android:layout_height="fill_parent">


<ImageView
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:src="@drawable/back" android:scaleType="fitXY" />


<LinearLayout>your views</LinearLayout>
</FrameLayout>

为了保持高宽比,你必须使用 android:scaleType=fitCenterfitStart等。使用 fitXY将不会保持原来的图像高宽比!

注意,这只适用于具有 src属性的图像,而不适用于背景图像。

要自定义背景图像缩放创建如下资源:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center"
android:src="@drawable/list_bkgnd" />

然后,如果用作背景,它将在视图中居中。还有其他标志: http://developer.android.com/guide/topics/resources/drawable-resource.html

当使用 setBackgroundDrawable方法设置 ImageView 的 Drawable 时,图像将始终按比例缩放。像 adjustViewBounds或不同的 ScaleTypes这样的参数将被忽略。唯一的解决方案,以保持高宽比我发现,是重新调整后加载 ImageView你的绘图。下面是我使用的代码片段:

// bmp is your Bitmap object
int imgHeight = bmp.getHeight();
int imgWidth = bmp.getWidth();
int containerHeight = imageView.getHeight();
int containerWidth = imageView.getWidth();
boolean ch2cw = containerHeight > containerWidth;
float h2w = (float) imgHeight / (float) imgWidth;
float newContainerHeight, newContainerWidth;


if (h2w > 1) {
// height is greater than width
if (ch2cw) {
newContainerWidth = (float) containerWidth;
newContainerHeight = newContainerWidth * h2w;
} else {
newContainerHeight = (float) containerHeight;
newContainerWidth = newContainerHeight / h2w;
}
} else {
// width is greater than height
if (ch2cw) {
newContainerWidth = (float) containerWidth;
newContainerHeight = newContainerWidth / h2w;
} else {
newContainerWidth = (float) containerHeight;
newContainerHeight = newContainerWidth * h2w;
}
}
Bitmap copy = Bitmap.createScaledBitmap(bmp, (int) newContainerWidth, (int) newContainerHeight, false);
imageView.setBackgroundDrawable(new BitmapDrawable(copy));
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imageView.setLayoutParams(params);
imageView.setMaxHeight((int) newContainerHeight);
imageView.setMaxWidth((int) newContainerWidth);

在上面的代码片段中,将要显示的 Bitmap 对象是 你好,而 图片查看ImageView对象

需要注意的一点是布局参数 的更改。这是必要的,因为如果定义宽度和高度是为了包装内容,而不是为了填充父内容,那么 setMaxHeightsetMaxWidth就会产生差异。另一方面,填充父级是开头所需的设置,因为否则 containerWidthcontainerHeight的值都等于0。 因此,在你的布局文件中,你的 ImageView 会有这样的东西:

...
<ImageView android:id="@+id/my_image_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
...

Dweebo 的建议是有效的,但是在我看来这是没有必要的。 一个背景可以自己缩放。视图应该有固定的宽度和高度,如下例所示:

 < RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/black">


<LinearLayout
android:layout_width="500dip"
android:layout_height="450dip"
android:layout_centerInParent="true"
android:background="@drawable/my_drawable"
android:orientation="vertical"
android:padding="30dip"
>
...
</LinearLayout>
< / RelativeLayout>

可以尝试的一个选项是将图像放在 drawable-nodpi文件夹中,并将布局的背景设置为可绘制的资源 ID。

This definitely works with scaling down, I haven't tested with scaling up though.

这不是最好的解决方案,但正如有人建议的那样,你可以创建 FrameLayout 或 RelativeLayout,并使用 ImageView 作为伪背景——其他元素将位于它的上方:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">


<ImageView
android:id="@+id/ivBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="fitStart"
android:src="@drawable/menu_icon_exit" />


<Button
android:id="@+id/bSomeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="61dp"
android:layout_marginTop="122dp"
android:text="Button" />


</RelativeLayout>

ImageView 的问题在于,只有 scaleType 可用: 居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中,居中 (http://etcodehome.blogspot.de/2011/05/android-imageview-scaletype-samples.html)

在某些情况下,为了“缩放背景图像(保持它的长宽比)”,当你想要一个图像填充整个屏幕(例如背景图像)和屏幕的长宽比不同于图像的时候,必要的 scaleType 类型是 TOP _ CROP,因为:

CENTER _ CROP 使缩放后的图像居中,而不是将顶部边缘对齐到图像视图的顶部边缘,FIT _ START 适合屏幕高度而不是填充宽度。正如用户 Anke 注意到的,FIT _ XY 并不保持长宽比。

很高兴有人扩展了 ImageView 以支持 TOP _ CROP

public class ImageViewScaleTypeTopCrop extends ImageView {
public ImageViewScaleTypeTopCrop(Context context) {
super(context);
setup();
}


public ImageViewScaleTypeTopCrop(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}


public ImageViewScaleTypeTopCrop(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setup();
}


private void setup() {
setScaleType(ScaleType.MATRIX);
}


@Override
protected boolean setFrame(int frameLeft, int frameTop, int frameRight, int frameBottom) {


float frameWidth = frameRight - frameLeft;
float frameHeight = frameBottom - frameTop;


if (getDrawable() != null) {


Matrix matrix = getImageMatrix();
float scaleFactor, scaleFactorWidth, scaleFactorHeight;


scaleFactorWidth = (float) frameWidth / (float) getDrawable().getIntrinsicWidth();
scaleFactorHeight = (float) frameHeight / (float) getDrawable().getIntrinsicHeight();


if (scaleFactorHeight > scaleFactorWidth) {
scaleFactor = scaleFactorHeight;
} else {
scaleFactor = scaleFactorWidth;
}


matrix.setScale(scaleFactor, scaleFactor, 0, 0);
setImageMatrix(matrix);
}


return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
}


}

Https://stackoverflow.com/a/14815588/2075875

现在恕我直言,如果有人写自定义可绘制的比例图像这样的完美。然后可以作为背景参数。


Reflog 建议在使用之前对可绘制图纸进行预缩放。以下是如何进行的说明: Java (Android) : 如何在没有位图的情况下缩放绘图? 尽管它有缺点,但是升级后的可绘制/位图将使用更多的 RAM,而 ImageView 使用的动态扩展并不需要更多的内存。优点是处理器负载较少。

下面的代码使得位图与图像视图的大小完全相同。得到位图图像的高度和宽度,然后利用图像视图的参数计算出新的高度和宽度。这给你所需的图像与最佳的纵横比。

int bwidth=bitMap1.getWidth();
int bheight=bitMap1.getHeight();
int swidth=imageView_location.getWidth();
int sheight=imageView_location.getHeight();
new_width=swidth;
new_height = (int) Math.floor((double) bheight *( (double) new_width / (double) bwidth));
Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap1,new_width,new_height, true);
imageView_location.setImageBitmap(newbitMap)

有一个简单的方法可以从可绘制图中实现这一点:

Your _ draable. xml

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


<item android:drawable="@color/bg_color"/>
<item>
<bitmap
android:gravity="center|bottom|clip_vertical"
android:src="@drawable/your_image" />
</item>


</layer-list>

唯一的缺点是,如果没有足够的空间,你的图像将不会完全显示,但它将被剪辑,我无法找到一种方法来做到这一点直接从一个绘制。但是从我做的测试来看,它工作得非常好,而且它不会剪辑太多的图像。你可以玩更多的重力选项。

另一种方法是创建一个布局,其中使用 ImageView并将 scaleType设置为 fitCenter

使用图片作为布局的背景尺寸:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >


<ImageView
android:id="@+id/imgPlaylistItemBg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:maxHeight="0dp"
android:scaleType="fitXY"
android:src="@drawable/img_dsh" />


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >




</LinearLayout>


</FrameLayout>

你可以使用下列其中之一:

机器人: 地心引力 = 填充水平

或者

机器人: 地心引力 = “ fill _ 竖直 | 剪辑 _ 水平”

科特林:

如果您需要在视图中绘制位图,则缩放为 FIT。

您可以进行适当的计算来设置 bm 的高度等于容器并调整宽度,在这种情况下,bm 的宽高比小于容器的宽高比,或者在相反的情况下是相反的。

图片来源:

Example Image 1

Example Image 2

// binding.fragPhotoEditDrawCont is the RelativeLayout where is your view
// bm is the Bitmap
val ch = binding.fragPhotoEditDrawCont.height
val cw = binding.fragPhotoEditDrawCont.width
val bh = bm.height
val bw = bm.width
val rc = cw.toFloat() / ch.toFloat()
val rb = bw.toFloat() / bh.toFloat()


if (rb < rc) {
// Bitmap Width to Height ratio is less than Container ratio
// Means, bitmap should pin top and bottom, and have some space on sides.
//              _____          ___
// container = |_____|   bm = |___|
val bmHeight = ch - 4 //4 for container border
val bmWidth = rb * bmHeight //new width is bm_ratio * bm_height
binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth.toInt(), bmHeight)
}
else {
val bmWidth = cw - 4 //4 for container border
val bmHeight = 1f/rb * cw
binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth, bmHeight.toInt())
}