一组六个广义密度:
ldpi (low) ~120dpi
mdpi (medium) ~160dpi
hdpi (high) ~240dpi
xhdpi (extra-high) ~320dpi
xxhdpi (extra-extra-high) ~480dpi
xxxhdpi (extra-extra-extra-high) ~640dpi
从每个手机显示屏的维基页面
缩小到桶中,即如果ppi是300,那么它会进入hdpi桶,因为它少于320?
Galaxy S3 306ppi -> bucket hdpi
Nexus 4 318ppi -> bucket hdpi
Nexus 5 445ppi -> bucket xhdpi
Nexus 5X 432ppi -> bucket xhdpi
Nexus 6 493ppi -> bucket xxhdpi
Nexus 6P 518ppi -> bucket xxhdpi
这是解决屏幕尺寸的正确方法。
我问的原因是因为我创建了以下值目录资源:
values-hdpi/dimens
values-xhdpi/dimens
values-xxhdpi/dimens
values-xxxhdpi/dimens
在dimens.xml
我有不同的边距,并根据铲斗大小设置dp,即
<dimen name="network_quantity_margin_top">100dp</dimen>
我很想知道这是否是正确的方法。
答案 0 :(得分:41)
我问的原因是因为我创建了以下值目录资源。 (......) 在dimens.xml中,我有不同的边距,并根据桶大小设置dp。 (......) 我很想知道这是否是正确的方法。
我不确定为什么要根据密度在dp
中指定不同的边距。对于基线密度,将边距指定为dp
一次,已经为您处理了所有其他密度,这意味着在任何设备上显示边距的物理尺寸都是相同的。
如果您使用px
代替dp
(但不是),那么您必须自己为不同的屏幕进行缩放。
缩小到桶中,即如果ppi是300,那么它会进入hdpi桶,因为它少于320?
是的,但不是因为它小于320.如果有经验法则我会说它是四舍五入到最近的广义密度。请参阅此插图,了解Android如何将实际密度粗略地映射到广义密度(图不准确):
the documentation的相关部分是:
每个通用尺寸和密度涵盖一系列实际屏幕尺寸和密度。例如,两个报告屏幕大小正常的设备可能具有实际屏幕尺寸和纵横比,当手动测量时,这些尺寸和纵横比略有不同。同样,报告屏幕密度 hdpi 的两个设备可能具有略微不同的实际像素密度。 Android将这些差异抽象为应用程序,因此您可以提供针对通用大小和密度设计的UI,并让系统根据需要处理任何最终调整。
再说一遍,如果您只是编写应用程序,那么您应该不关心如何 Android这样做。你应该关心的是:
dp
或wrap_content
/ match_parent
中指定所有layout dimension值(文本可以在sp
中以额外匹配用户首选项,但除了文字之外别无其他),dp
或wrap_content
,Android会将它们缩放到具有正确的物理尺寸。)< / LI>
Android将lookup the best matching resource和then transparently handle根据需要对dp
单位进行任何缩放。将dp
单位转换为屏幕像素非常简单:px = dp * (dpi / 160)
。
注意实际密度而不是广义密度。后者仅为开发人员带来便利因为不可能为每个屏幕提供可绘制的内容。这样开发人员只需要提供3或4组图形,而Android会选择最接近的版本,并根据特定设备的需要进一步调整。 (现在可以使用一个矢量绘图而不是许多预先缩放的光栅图形,这意味着更好的质量和更小的尺寸。)
这是解决屏幕尺寸的正确方法。
不,不是。根据{{3}},您列出的所有设备都会比您预期的要高:
Galaxy S3 NA NA
Nexus 4 318 xhdpi
Nexus 5X 424 xxhdpi
Nexus 5 445 xxhdpi
Nexus 6 493 xxxhdpi
Nexus 6P 515 xxxhdpi
我从该列表中选取了其他一些设备,并根据实际物理密度绘制了不同设备如何落入密度桶中。
Chromebox 30 101 mdpi
Chromebook 11 135 mdpi
Samsung Galaxy Tab 10 149 mdpi
Nexus 7 '12 216 tvdpi
Android One 218 hdpi
Chromebook Pixel 239 xhdpi
Nexus 9 288 xhdpi
Nexus 10 299 xhdpi
Moto X 312 xhdpi
Nexus 4 318 xhdpi
Nexus 7 '13 323 xhdpi
Moto G 326 xhdpi
Dell Venue 8 359 xhdpi
LG G2 424 xxhdpi
Nexus 5X 424 xxhdpi
HTC One M8 441 xxhdpi
Nexus 5 445 xxhdpi
Nexus 6 493 xxxhdpi
Nexus 6P 515 xxxhdpi
LG G3 534 xxhdpi
你可以看到,除了一些值得注意的例外情况,选择最接近的广义密度的规则成立。
Nexus 6和6P的例外情况被列为xxxhdpi
,即使LG G3具有更高的物理密度并且仍远离640px / in。 Android One为hdpi
,但仅比Nexus 7 '12 tvdpi
稍微密集一些。 Chromebox 30和Chromebook Pixel(不可否认,不是Android)已分配给存储分区mdpi
和xhdpi
,即使它们分别低于ldpi
和hdpi
。
答案 1 :(得分:10)
我很想知道这是否是正确的方法。
你主要是正确。
问题出在这一部分:
我问的原因是因为我创建了以下值目录资源:
values-hdpi/dimens
values-xhdpi/dimens
values-xxhdpi/dimens
values-xxxhdpi/dimens
在dimens.xml中,我有不同的边距,并根据桶大小设置dp,即
<dimen name="network_quantity_margin_top">100dp</dimen>
dp
的目的通过定义values-hdpi/dimens
等文件夹而失败。 密度像素(按设计,与设备无关 - 100dp 在 dpi = 240 的设备上看起来像一样宽/长在 dpi = 480 的设备上。因此,如果您希望自己的应用看起来一致,请不要为不同的屏幕密度提供不同的尺寸。
考虑这一点的正确方法是认识到受不同屏幕密度影响的唯一资源是drawable
。与密度= 480的屏幕相比,dpi = 240的屏幕上的drawable
将两倍。我确信您提供的文件夹为drawable-hdpi
, drawable-xhdpi
等来处理这个问题。对于其他所有内容,尤其是维度,请使用dp
。对于文字大小,请使用scaled-pixels - sp
。
更重要的是,您应该担心可用于Android的不同屏幕尺寸的范围。与5英寸手机相比,你如何使用10英寸设备上的所有额外屏幕空间?您应该更关注-normal
,-large
,xlarge
等限定符。
总结:
density pixels
时,它们的屏幕密度无关紧要。 drawable
资源,将其缩放版本放在您希望支持的存储区中。请记住,如果您没有为某个存储桶提供资源(比如说drawable-hdpi
),那么android会缩小您的drawables drawable-xhdpi
文件夹(如果定义了drawable-xhdpi)。反之亦然:如果您已将所有可绘制的内容放在drawable-xhdpi
中,则android会在xxhdpi
设备上向上扩展您的drawable。结果将是模糊的图形 - 因为扩大规模。我知道这里有一点陡峭的坡度:)。所以,如果你需要澄清一些,请给我留言。
答案 2 :(得分:6)
来自Android文档:
在某些情况下,您需要以dp表示尺寸,然后再表示 将它们转换为像素。想象一下滚动或滚动的应用程序 用户的手指移动后识别出手势 至少16像素。在基线屏幕上,用户必须移动16个像素 / 160 dpi,相当于之前的1/10英寸(或2.5 mm) 手势得到认可。在具有高密度显示器的设备上 (240dpi),用户必须移动16像素/ 240 dpi,等于 1/15英寸(或1.7毫米)。距离要短得多 因此,应用对用户来说似乎更敏感。
要解决此问题,必须在代码中表示手势阈值 dp然后转换为实际像素。例如:
// The gesture threshold expressed in dp
private static final float GESTURE_THRESHOLD_DP = 16.0f;
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);
// Use mGestureThreshold as a distance in pixels...
DisplayMetrics.density字段指定您必须的比例因子 用于根据当前屏幕将dp单位转换为像素 密度。在中密度屏幕上,DisplayMetrics.density等于 1.0;在高密度屏幕上,它等于1.5;在超高密度屏幕上,它等于2.0;在低密度屏幕上,它等于0.75。 此数字是您应该将dp单位乘以的因子 为了获得当前屏幕的实际像素数。 (然后加 当转换为整数时,0.5f将图形向上舍入到最接近的整数。)有关更多信息,请参阅 DisplayMetrics上课。
答案 3 :(得分:2)
你必须以dp而不是dpi(每英寸点数)来处理有关屏幕宽度的资源
例如nexus 5 1920 X 1080 480 dpi它使用xxhdpi 和nexus 6p 2560 X 1440 560 dpi它使用的是xxhdpi而不是xxxhdpi !!
处理它使用最宽的资源&#34; drawable-swXXXdp&#34;
dp中的宽度= pixle中的宽度/(dpi / 160) dp = 1440 /(560/160)= ~411
create drawable-sw411dp
答案 4 :(得分:1)
PPI(每英寸像素)和DPI(每英寸点数)意味着同样的事情,因为它们是密度的屏幕;因此,您对PPI与DPI的关系是正确的。
可以找到详细解释here。本文的关键部分如下:
屏幕密度被引用为每英寸像素数,PPI,并且是 适合一英寸的像素数。数字越高那么 更清晰的图像在显示屏上显示,因此消费者会考虑使用 高PPI在购买设备时具有优势。有时候 图被引用为 Dots Per Inch ,DPI ......
答案 5 :(得分:0)
有点晚,但这对其他读者可能有用。屏幕密度和Android用于从中选择资源的“存储桶”可能会造成混淆。 Google的文档非常密集,在编写代码时需要大量工作才能将其精简为有用的东西。部分原因是有几个因素,它们告诉您有关屏幕密度和倾斜度的所有信息。但是简短的答案是这样。
基本上,dpi是您的定义因素,(如果您依赖其他因素,例如小/中/大),这不是您的答案。否则,我发现this的答案非常有用且简单。这是我从应用启动时运行的各种来源收集的一些代码,用于确定显示信息。
屏幕密度告诉我设备支持的dpi级别。
float density = context.getResources().getDisplayMetrics().density;
接下来,我有一个简单的设备指标方法来告诉我有关屏幕的信息。 (请注意,我正在使用Timber logger)。
protected static void checkDeviceSize(AppCompatActivity context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
Display display = context.getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
float density = context.getResources().getDisplayMetrics().density;
float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels / density;
String dpiName = getDpiName(density);
Timber.e("density :" + density + " [" + dpiName + "]");
Timber.e("height dp:" + dpHeight + ", (" +outMetrics.heightPixels + "px)");
Timber.e("width dp :" + dpWidth + ", (" + outMetrics.widthPixels + "px)");
}
我也有这个简单的帮助程序方法,该方法确定DPI名称以支持上述方法。
public static final String DPI_LDPI = "ldpi";
public static final String DPI_MDPI = "mdpi";
public static final String DPI_HDPI = "hdpi";
public static final String DPI_XHDPI = "xhdpi";
public static final String DPI_XXHDPI = "xxhdpi";
public static final String DPI_XXXHDPI = "xxxhdpi";
public static final String DPI_TVDPI = "tvdpi";
private static String getDpiName(float density) {
String result = "undefined";
if (density < 1.0) {
result = DPI_LDPI;
} else if (density == 1.0f) {
result = DPI_MDPI;
} else if (density <= 1.3f) {
result = DPI_TVDPI;
} else if (density <= 1.5f) {
result = DPI_HDPI;
} else if (density <= 2.0f) {
result = DPI_XHDPI;
} else if (density <= 3.0f) {
result = DPI_XXHDPI;
} else if (density <= 4.0f) {
result = DPI_XXXHDPI;
}
return result;
}
最后this video仍然与今天有关。