To better understand how you can support multiple densities when manipulating graphics at runtime, you should understand that the system helps ensure the proper scale for bitmaps in the following ways:
-
Pre-scaling of resources (such as bitmap drawables)
Based on the density of the current screen, the system uses any size- or density-specific resources from your application and displays them without scaling. If resources are not available inthe correct density, the system loads the default resources and scales them up or down as needed tomatch the current screen‘s density. The system assumes that default resources (those from adirectory without configuration qualifiers) are designed for the baseline screen density (mdpi),unless they are loaded from a density-specific resource directory. Pre-scaling is, thus, what thesystem does when resizing a bitmap to the appropriate size for the current screendensity.
If you request the dimensions of a pre-scaled resource, the system returns valuesrepresenting the dimensions after scaling. For example, a bitmap designed at 50x50 pixelsfor an mdpi screen is scaled to 75x75 pixels on an hdpi screen (if there is no alternative resourcefor hdpi) and the system reports the size as such.
There are some situations in which you might not want Android to pre-scalea resource. The easiest way to avoid pre-scaling is to put the resource in a resource directorywith the
nodpi
configuration qualifier. For example:res/drawable-nodpi/icon.png
When the system uses the
icon.png
bitmap from this folder, it does not scale itbased on the current device density. -
Auto-scaling of pixel dimensions and coordinates
An application can disable pre-scaling by setting
android:anyDensity
to"false"
in the manifest or programmatically for aBitmap
by settinginScaled
to"false"
. In this case, the system auto-scales any absolute pixel coordinates and pixeldimension values at draw time. It does this to ensure that pixel-defined screen elements are stilldisplayed at approximately the same physical size as they would be at the baseline screen density(mdpi). The system handles this scaling transparently to the application and reports the scaledpixel dimensions to the application, rather than physical pixel dimensions.For instance, suppose a device has a WVGA high-density screen, which is 480x800 and about thesame size as a traditional HVGA screen, but it‘s running an application that has disabledpre-scaling. In this case, the system will "lie" to the application when it queries for screendimensions, and report 320x533 (the approximate mdpi translation for the screen density). Then, whenthe application does drawing operations, such as invalidating the rectangle from (10,10) to (100,100), the system transforms the coordinates by scaling them the appropriate amount, and actuallyinvalidate the region (15,15) to (150, 150). This discrepancy may cause unexpected behavior ifyour application directly manipulates the scaled bitmap, but this is considered a reasonabletrade-off to keep the performance of applications as good as possible. If you encounter thissituation, read the following section about Converting dp units to pixelunits.
Usually, you should not disable pre-scaling. The best way to support multiplescreens is to follow the basic techniques described above in How to SupportMultiple Screens.
If your application manipulates bitmaps or directly interacts with pixels on the screen in someother way, you might need to take additional steps to support different screen densities. Forexample, if you respond to touch gestures by counting the number of pixels that a fingercrosses, you need to use the appropriate density-independent pixel values, instead of actualpixels
If your application creates an in-memory bitmap (a Bitmap
object), the system assumes that
the bitmap is designed for the baseline medium-density screen, by default, and
auto-scales the bitmap at draw time. The system applies "auto-scaling" to
a Bitmap
when the bitmap has
unspecified density properties. If you don‘t properly account for the current
device‘s screen density and specify the bitmap‘s density properties, the
auto-scaling can result in scaling artifacts the same as when you don‘t provide
alternative resources.
To control whether a Bitmap
created at runtime is scaled
or not, you can specify the density of the bitmap withsetDensity()
, passing a density constant
fromDisplayMetrics
, such as DENSITY_HIGH
or DENSITY_LOW
.
If you‘re creating a Bitmap
using BitmapFactory
, such as from a file or a
stream, you can use BitmapFactory.Options
to define
properties of the bitmap as it already exists, which determine if or how the
system will scale it. For example, you can use the inDensity
field to define the
density for which the bitmap is designed and the inScaled
field to specify whether the
bitmap should scale to match the current device‘s screen density.
If you set the inScaled
field
to false
, then you disable any pre-scaling that the system may
apply to the bitmap and the system will then auto-scale it at draw time. Using
auto-scaling instead of pre-scaling can be more CPU expensive, but uses less
memory.
译文:
为了更好理解当你在运行时操作图片该如何支持多种密度的屏幕 ,你应该理解系统以以下几种方式帮助确保图片以何时的尺寸展现:
1. Pre-scaling 预伸缩 资源(比如图片资源)
基于当前屏幕的密度,系统从你的res 中选用 screen size(以下简称size) 标签或者 screen pixel density (以下简称density) 匹配的资源,并不进行伸缩地展现它。如果并没有正确的density 匹配资源,系统加载默认的文件夹,然后将伸展或缩小以适应当前的屏幕密度。系统将假设默认的资源(不带标签的)是为基准屏幕(mdpi)设计的,除非他们是从一个density指定的(即带density 标签的)。预伸缩就是指系统当将图片调整尺寸以适应当前屏幕的过程。
如果你请求一个预伸缩资源的尺寸值,系统将返回预伸缩后的资源的尺寸值。比如,一个图片在mdpi 屏幕本来是50x50 的,在hdpi 将被伸展到75x75 (如果这时候hdpi 并没有对应的图片资源) ,系统将返回75x75的数值。
某些情况下,你也许不希望系统对图片进行预伸缩,最简单的避免预伸缩的办法是将资源放在nodpi 文件夹下。
2. Auto-Scaling 自动伸缩像素面积和坐标
一个程序能关闭pre-scaling,方法是:在manifest 中设置android:anyDensity ="false" 或者在代码中对bitmap 设置其inScaled 为 "false" 。在这种情况下,系统在绘制时将自动伸缩任何绝对的像素坐标以及像素的面积值。以此来确保像素确定的屏幕元素,在不同屏幕下仍然显示出接近基准(mdpi)屏幕同样大小的尺存,系统隐形透明地进行此变化,并将向外返回变化后的尺寸值,而非原图的物理尺寸。
比如,假设有一个WVGA 高密度设备,屏幕是480x800, 与传统HVGA 屏幕类似,但是他运行了一个关闭了pre-scaling (预伸缩)机制的app。在这种情况下,当app 向系统请求屏幕尺寸的时候,系统将向app”撒谎“ 返回320x533(近似mdpi 的尺寸值。mdpi : hdpi = 4:6 )。 然后,当App 在进行绘制操作时,比如绘制一个从 (10,10)到(100,100)绘制一个矩形,系统将改变绘制的坐标和像素面积,实际上将绘制出一个从(15,15)到(150,150)的矩形。这种差异在你直接绘制伸缩过的图片时可能导致不可预知的结果,但是这被认为是对保持App 尽量良好展示效果的一种合理的折中。如果你遇到这个问题,建议你阅读 Converting dp units to pixelunits. 章节。
大部分情况下,你不该关闭pre—scaling 机制。支持多尺寸屏幕的最好方法是跟随以下章节介绍的良好规范:How to SupportMultiple Screens.
如果你的App 在屏幕上操作图片或者进行与直接与像素直接交互的操作,你可能还需要额外的一些操作来支持多种屏幕密度(screen pixel density)。比如,你在计算用户手指在屏幕上划过的距离时,可能需要与密度无关的数值(物理上的距离值),而非实际的像素值。
如果你的App 创建了一个保存在内存的图片(一个Bitmap 对象),系统将假设你的图片是为基准(mdpi)的屏幕使用的,然后在绘制时将对它进行自动伸缩。当没有设置density 属性时,系统使用”auto-scaling“ 对图片进行变化。当不正确地计算屏幕密度并给bitmap 对象设置density 属性时,auto—scaling 机制将可实现与不提供合适资源依赖pre-scaling 变化一样的伸缩效果。
为了对是否伸缩在运行时创建出来的图片进行控制,你可以通过setDensity()为bitmap
设置density属性,传入一个来自DisplayMetrics
,的density
常量。
如果你用BitmapFactory
,
创建来自文件或者来自数据流的一张图片,你可以使用 BitmapFactory.Options 来设置bitmap的属性,以此来决定系统是否对它进行变化。比如,你使用inDensity
来设置bitmap 的density,使用inScaled 来指定bitmap 是否该被pre-scaling
来适配当前屏幕。
如果你将inScaled 设置为false,那么,你就关闭了pre-scaling 机制对这种图片的使用,然后系统在绘制时,将对它进行auto-scaling。使用auto-scaling 替代pre-scaling 将耗费更多cpu 资源,不过能减少内存消耗。
Android 屏幕适配 Supporting Multiple Screens | Android Developers,布布扣,bubuko.com
Android 屏幕适配 Supporting Multiple Screens | Android Developers
原文:http://www.cnblogs.com/chikeong/p/3643733.html