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


134

在布局上,我想将背景图像(保持其纵横比)缩放到创建页面时分配的空间。有谁知道如何做到这一点?

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


我遇到了这个问题,并按照Dweebo的建议进行了Anke建议的更改:将fitXY更改为fitCenter。运作良好。

Answers:


90

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

<?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


6
我尝试使用位图,但是图像只是居中,而不是按Sam的要求进行缩放。当我使用ImageView时,它的效果很漂亮,没有混乱。(nb:在这种情况下,我也不滚动。)为了缩放图像,我将使用什么扩展位图?
Joe D'Andrea

7
可能的值为:“ top” | “底部” | “左” | “正确” | “ center_vertical” | “ fill_vertical” | “ center_horizo​​ntal” | “ fill_horizo​​ntal” | “中心” | “填充” | “ clip_vertical” | “ clip_horizo​​ntal”
Aleks N.

30
这些参数都不能通过保持纵横比来缩放位图,因此答案是错误的。
玛拉基亚斯2014年

7
尊敬的Malachiasz:“中心”确实尊重长宽比。但是它不会按比例缩小图像。这意味着使用它有些危险。取决于目标的分辨率,您永远不知道事情将如何精确缩放。Google的另一半解决方案。

2
有没有办法添加scaleType属性?
ademar111190 2014年

57

尚未尝试完全执行您想要的操作,但是您可以使用缩放ImageView 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>

1
是否可以在Surface上执行此操作。如果不是,是否可以使用FrameLayout显示预览(对于记录器应用程序)?
Namratha 2010年

1
@dweebo:您尝试过吗?它似乎对我不起作用。
speedplane

3
由于使用两个UI组件而不是一个UI组件,这是一个不好的主意,特别是对于诸如ListView这样的繁忙组件而言。滚动时很可能会遇到麻烦。正确的解决方案:stackoverflow.com/a/9362168/145046
Aleks N.

我尝试了fitCenter和centerCrop的scaleType(以及针对不同密度的drawable / image的一些变体),并且它起作用了!哪种比例尺类型对我来说都是有意义的-我怀疑,更多是基于图像的个人喜好。请注意,我使用merge而不是FrameLayout,在我的特殊情况下没有滚动。
Joe D'Andrea

2
centerInside是适当的,而不是fitXY,如fitXY不保留所述图像的纵横比
Malachiasz

35

有一个简单的方法可以从drawable中做到这一点:

your_drawable.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并将其设置scaleTypefitCenter


2
这个解决方案绝对是我长期以来一直在寻找的主题,以替换主题的背景属性,并在视图具有或不具有选项卡时避免图像缩放不同。感谢您分享。
比布

1
它显示错误:error: <item> must have a 'name' attribute.
德米特里(Dmitry)'18年

thx @ lonutNegru,+ 1表示拯救了我的一天:)
Ravi Vaniya

18

要保持长宽比,您必须使用android:scaleType=fitCenterfitStart等。使用fitXY将不会保持图像的原始长宽比!

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


18

使用图像作为背景尺寸进行布局:

<?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>

谢谢!也android:scaleType="centerCrop"可以。
CoolMind

5

当使用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);

在上面的代码段中,bmp是要显示的Bitmap对象,而imageViewImageView对象

要注意的重要一点是布局参数的更改。这是必要的,因为setMaxHeightsetMaxWidth只会让若宽度和高度定义的包裹内容,不填充父的差异。在另一方面填充父母是在开始时所需的设置,因为否则的话containerWidth,并containerHeight都将具有值等于0。所以,在布局文件,你将有这样的事情为您的ImageView:

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

4

这不是性能最高的解决方案,但是正如有人建议的那样,您可以创建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是:CENTER,CENTER_CROP,CENTER_INSIDE,FIT_CENTER,FIT_END,FIT_START,FIT_XY,MATRIX(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

现在,如果有人编写自定义Drawable来缩放图像,恕我直言将是完美的。然后可以用作背景参数。


Reflog建议在使用可绘制图形之前对其进行预缩放。以下是如何操作的说明: Java(Android):如何在不使用位图的情况下缩放可绘制对象? 尽管它有缺点,但放大的可绘制/位图将使用更多的RAM,而ImageView使用的即时缩放则不需要更多的内存。优点是可以减少处理器负载。


好一个!完全符合我的要求:通过按比例增加宽度并裁剪图像底部来填充整个屏幕的背景图像。
CMash 2015年

4

以下代码使位图与imageview的大小完全相同。获取位图图像的高度和宽度,然后借助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)

2

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>

2
我的理解是,背景将扩大以填充视图,但不会缩小。
Edward Falk 2014年

1

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

这肯定可以按比例缩小,但是我还没有测试按比例放大。


0

科特林:

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

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

图片:

示例图片1

示例图片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())
}

-4

您必须先预先缩放该可绘制对象,然后才能将其用作背景


这真的是唯一的选择吗?是否没有可以放置ImageView的容器来指定显示尺寸?
GrkEngineer 2010年

我在SurfaceView上也遇到了麻烦
AZ_

3
有没有像iOS上的宽宽适合,宽高填充,左上方,顶部等?真烂..
Maciej Swic

正如@Aleksej所说,这是不正确的答案。
学习者2016年

-5

您可以使用以下之一:

android:gravity =“ fill_horizo​​ntal | clip_vertical”

要么

android:gravity =“ fill_vertical | clip_horizo​​ntal”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.