【问题标题】:Using just one (high density) image to scale to width in a scrollview for all devices仅使用一个(高密度)图像在所有设备的滚动视图中缩放到宽度
【发布时间】:2025-11-27 03:05:01
【问题描述】:

我正在开发一种说明应用程序。它使用带有 ScrollvView、垂直 LinearLayout 和一些 TextViews / ImageViews 的片段来解释产品的工作原理。

这些图像只是简单的矢量图形,由于 Android 上缺乏矢量图像支持,我将其保存为 png。这是一个例子:

图像总是使用android:scaleType="fitXY"(纵向和横向)填充屏幕,而滚动查看器负责其余部分(在图像视图中使用android:adjustViewBounds="true"以防止滚动到图像的原始大小)。

我阅读了 Google 的指导方针,以针对不同的分辨率和密度使用不同的版本,但这似乎对我的目的进行了过度设计。 我的想法是只提供可绘制文件夹中图像的一张高分辨率(2000 像素宽度)图像,并让 Android 自动缩放完成其余工作。

我能想到的唯一问题是内存。但我不太确定内部是如何工作的。如果 OutOfMemory 仅在显示图像时发生,它应该不是问题,因为自动缩放首先命中。

如果缩放器可能遇到内存问题,我正在考虑使用 3 个不同宽度的图像版本(即 800 像素、1500 像素和 2200 像素)并将它们放在不同的资源目录中。 虽然这似乎不可能...... 资源目录的 Android Studio 向导有一个“最小屏幕宽度”选项,但它仅适用于 dp(与密度无关的像素)!我想要一个真实设备像素的资源文件。我希望 Android 采用最接近的拟合,如果找不到完全匹配的,不要回退到默认的。 我的图像不关心密度,因为它们总是填满屏幕。

简而言之:

  • 只提供一个小文件大小的大像素图像有问题吗?

  • 如果是,如何设置设备像素资源目录?

应用的本质已经包含大量图像。这就是为什么我不想复制每个几次,这会增加要处理的图像数量。该应用适用于 API 11 及更高版本。

【问题讨论】:

    标签: android image scrollview image-scaling autoscaling


    【解决方案1】:

    我终于找到了一种解决方案,可以将一张图像按比例缩放到设备宽度,而不会出现内存问题。

    1. 首先,您必须以相当高的分辨率绘制图像 (my_image.png)
    2. 仅将此图像放入 drawable-xxhdpi 文件夹。
    3. 使用 this 很棒的答案扩展 Android ImageView 类。
    4. 在您的布局中使用它,如下所示:

    这是适合我的布局:

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:fillViewport="true">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <TextView
                android:id="@+id/main_text_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/hello_world" />
    
            <my.package.name.DynamicImageView
                android:id="@+id/main_image"
                android:adjustViewBounds="true"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/main_text_view"
                android:src="@drawable/my_image"
                android:scaleType="fitXY"/>
    
            <my.package.name.DynamicImageView
                android:id="@+id/main_image2"
                android:adjustViewBounds="true"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/main_image"
                android:src="@drawable/my_image"
                android:scaleType="fitXY"/>
    
            <TextView
                android:id="@+id/main_text_view2"
                android:layout_below="@id/main_image2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/hello_world" />
    
        </RelativeLayout>
    </ScrollView>
    

    更多最终信息: 在找到第 3 点的解决方案之前,我对第 2 点(将图像放入哪个文件夹)进行了大量测试。

    如果您将图像放在标准的drawable 文件夹中,则无需第 3 点即可进行缩放,但您可能会在旧设备上遇到 OutOfMemory 异常,因为 android 会尝试缩放已经很大的图像(Android 认为 drawable 仅小图像而不检查它们的大小)。

    当图像位于drawable-xxhdpi 文件夹中时,Android 知道其高分辨率,并且仅在必要时进行缩小。但它不会将图像缩放到密度拟合设备上的宽度!例如,在 Nexus 10 中,图像以其原始大小和比例绘制 - 与您为 scaleType 设置的内容无关(我认为它与 inTargetDensity 有关,如inScaled 描述中所述)。

    这里要记住的重要一点是,我必须在整个内容周围使用ScollView。当不涉及ScrollView 时,您可能会找到其他一些解决方案。

    最后,您也可以使用 drawable-xxxhdpi 文件夹,但它是在 API 19 中引入的。我试过了,它也适用于较低的 API。 Apparently Android 构建工具 19.1.0 及更高版本负责处理较低的 API 版本。

    我希望这对某人有所帮助...

    【讨论】:

      最近更新 更多