java - android:scaleType =“center”不能满足我的要求:dp和px如何工作?

标签 java android android-layout imageview scaletype

我正在尝试完成必须可以想象的最简单的事情。我有菜单的背景图片。我希望在屏幕上显示尽可能多的图像,每个像素一个像素,并且没有缩放比例。

据我所知,这正是scaleType =“ center”应该完成的工作。不幸的是,无论我做什么,它都拒绝做我想要的事情,而只显示图像的一小部分。

为了用实数阐明,我在sw320dp drawables文件夹中有一个720x1280px的背景图像,由我的sw320dp布局调用。对于介于320x480px和720x1280px之间的任何屏幕尺寸,他们应该调用该布局并显示该背景图像的一部分。因此,480x800px的Nexus One应该显示图像的480x800px的一部分。为此,我有:

<ImageView
android:id="@+id/menuBackground"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
app:srcCompat="@drawable/menubackground_w720" />


不幸的是,它不起作用。取而代之的是,它仅显示图像的一小部分,大约等于320x480px,长宽比为正负。

经过反复的咒骂和扯断之后,我将可能性缩小为三种合理的理论:


我正在以一种愚蠢的方式做着非常,非常,非常简单的错误。
我从根本上不了解dp的工作原理以及可扩展的布局。
这个世界是一场怪诞的,非理性的洛夫克拉夫特式噩梦,其中没有任何意义,我注定永远在无望的疯狂圈子中追逐自己的尾巴。


假设第三个选项(即使为true)是“无法解决的”,那么如果有人可以告诉我这是一个还是两个选项,并将我链接到适当的最新资源,我将不胜感激。感谢您的协助!

最佳答案

tl; dr


  我希望在屏幕上显示尽可能多的图像,每个像素一个像素,并且没有缩放比例。


将图像移到res/drawable-nodpi/目录。




  经过反复的咒骂和扯断之后,我将可能性缩小为三种合理的理论:
  
  
  我正在以一种愚蠢的方式做着非常,非常,非常简单的错误。
  我从根本上不了解dp的工作原理以及可扩展的布局。
  这个世界是一场怪诞的,非理性的洛夫克拉夫特式噩梦,其中没有任何意义,我注定永远在无望的疯狂圈子中追逐自己的尾巴。
  


我认为#2可能是最接近真相的。没关系;情况很复杂。

让我们开始考虑以下图像:

enter image description here

我在这里对其进行了调整,以使其在回答中不会占用大量空间,但是在我的计算机上为1000x1000像素。每个黑色或白色正方形均为100x100像素。这将使我们很容易推断出应用程序中正在发生的事情。

接下来,我制作了一个非常简单的应用程序:它仅显示200x200 dp的ImageView,而没有其他显示。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}




<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#eee">

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:scaleType="center"
        android:src="@drawable/checkerboard"/>

</FrameLayout>


我将checkerboard.png放入res/drawable/目录,然后运行该应用程序。我的仿真器是Nexus 5X,它(根据this site)的屏幕分辨率为1080x1920像素。这是我看到的:

enter image description here

嗯这导致了一些问题:

为什么200 dp宽的ImageView占据一半的屏幕?

dp单元的明确目的是允许视图在不同设备上的物理尺寸大致相同。这里的一个挑战是不同的设备可能具有不同的显示密度。一台手机可能具有适合于物理英寸的320像素的高分辨率显示屏,而另一部手机可能具有仅适合于物理英寸的120像素的高分辨率显示屏。

Android的基准是160 dpi。在此密度下,1 dp == 1 px。如果您的设备具有更高的密度,则1 dp等于大于1 px。 Nexus 5X的密度约为423 dpi,因此在我的布局中每1 dp使用约2.6像素。因此,在此特定仿真器上,200x200 dp表示大约520x520像素。

但是为什么我的.png只显示200x200像素的图像?

在不同设备上使事物具有相同物理尺寸的另一个挑战是如何处理图像。我们仅向系统提供了一个checkerboard.png文件,但是我们知道ImageView在不同设备上将具有不同的像素尺寸。剩下两个选择:

系统无法执行缩放。如果可以,那么我在Nexus 5X上会看到大约520x520像素的图像,但是仍然在运行Nexus One(252 dpi)的人只能看到大约315x315像素的图像。整个ImageView的物理尺寸大致相同,但是我们两个人会看到完全不同的图像内容。

或者,系统可以按比例放大图像。现在,它执行与图像数据本身上dp到px相同的缩放比例。完成此操作后,Nexus 5X和Nexus One都会看到200x200像素的图像数据。但是,在Nexus 5X上,缩放伪影会变得更糟,因为系统必须将图像按比例放大才能满足更高的显示密度。

我应该怎么做才能解决?

这取决于您的最终目标。如果您只想提供一个.png文件,并且希望系统不按比例放大文件(即,无论显示密度如何,任何设备上的像素都应为1px,以显示图像的1px),则应移动。 png到res/drawable-nodpi/目录。

https://developer.android.com/guide/topics/resources/providing-resources.html


  nodpi:这可用于您不想缩放以匹配设备密度的位图资源。


如果对示例应用程序执行此操作,则在运行它时会看到以下内容:

enter image description here

确实,我们看到了大约520x520像素的图像。

另一方面,如果您希望每个用户看到相同的物理图像,但又希望避免缩放伪影,则应提供图像文件的多种分辨率。

考虑一下从Google的Material Icon存储库下载图标的.png版本时会发生什么情况。假设我们采用ic_face.png。您得到的目录结构如下所示:

android/
    drawable-mdpi/
        ic_face_black_24dp.png (24x24 pixels)
    drawable-hdpi/
        ic_face_black_24dp.png (36x36 pixels)
    drawable-xhdpi/
        ic_face_black_24dp.png (48x48 pixels)
    drawable-xxhdpi/
        ic_face_black_24dp.png (72x72 pixels)
    drawable-xxxhdpi/
        ic_face_black_24dp.png (96x96 pixels)


这是在以不同的分辨率提供同一图像的不同版本。具有高显示密度的设备将拍摄与其密度最匹配的图像,然后仅将其缩放到很小的数量。这大大减少了缩放伪影。

进一步阅读

https://developer.android.com/guide/topics/resources/providing-resources.html

https://developer.android.com/guide/practices/screens_support.html

关于java - android:scaleType =“center”不能满足我的要求:dp和px如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48646050/

相关文章:

Java extras 包返回空值

android - 在 android 中,当方向改变时,背景图像不会改变

java - 在 JNI 客户端应用程序中设置较小的 JVM 堆大小

java - ConcurrentlinkedQueue 类型不是通用的;它不能用参数 <Integer> 进行参数化

c++ - 在 C++ 中检测本地网络上的客户端-服务器连接设备

android:如何从推特上获取趋势?

css - Android 和 iPad 都不尊重视口(viewport)

android - 高程不适用于 LinearLayout

java - 使用元数据创建 jpeg 文件

android - 按钮、标题和副标题中的两个文本