机器人:scaleType ="中心"没有做我认为应该做的事情:dp vs px是如何工作的?

时间:2018-02-06 15:06:00

标签: 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加上或减去一点宽高比。

经过多次咒骂和撕裂我的头发后,我把可能性缩小到三个合理的理论:

  1. 我以愚蠢的方式做了一件真的,真的,难以置信的简单错误。
  2. 我从根本上不了解dp的工作原理以及可扩展的布局。
  3. 这个世界是一个奇异的,非理性的Lovecraftian梦魇,其中没有任何意义,我注定永远在无望的疯狂圈子里追逐自己的尾巴。
  4. 假设第三个选项,即使是真的,也是一个“不会解决”的问题,如果有人可以告诉我它是选择一个还是两个,我会很感激,并将我链接到适当的最新资源。谢谢你的帮助!

2 个答案:

答案 0 :(得分:2)

TL;博士

  

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

将您的图片移至res/drawable-nodpi/目录。

  

经过多次咒骂和撕裂我的头发后,我把可能性缩小到三个合理的理论:

     
      
  1. 我正以愚蠢的方式做一些非常,非常,非常简单的错误。
  2.   
  3. 我从根本上不了解dp的工作原理以及可扩展的布局。
  4.   
  5. 这个世界是一个奇异的,非理性的Lovecraftian梦魇,其中没有任何意义,我注定永远在无望的疯狂圈子里追逐自己的尾巴。
  6.   

我认为#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

答案 1 :(得分:0)

尝试使用

android:scaleType="centerCrop"

我在使用图像浏览时遇到了同样的问题,这每次都解决了我的问题。