DisplayMetrics.scaledDensity在Android中实际返回什么?

我试图了解Android中的sp单元,但我无法弄清楚它是如何工作的。 文件说:

SP

与比例无关的像素 – 这与dp单位类似,但它也可以根据用户的字体大小首选项进行缩放。 建议您在指定字体大小时使用此单位,以便根据屏幕密度和用户偏好调整它们。

使用DisplayMetrics可以获得scaledDensity ,它是:

显示屏上显示的字体缩放系数。 这与密度相同,除了它可以在运行时根据用户对字体大小的偏好以较小的增量进行调整。

因此,鉴于此信息,我假设scaledDensity将随着我更改系统字体大小而改变,并且我可以使用此信息来了解1dp和1sp之间的比率( scaledDensity / density )。

但是,当我在手机(Nexus 4)上测试时,我没有得到我期待的结果。 DisplayMetrics.scaledDensity始终返回相同的值(等于DisplayMetrics.density),无论我设置手机使用的字体大小(通过settings -> accessibility -> use large fontsettings -> display -> font size )。

当我更改字体设置时,我指定的字体会改变大小,因此sp单元按预期工作,但scaledDensity值根本不会改变。

我用来获取scaledDensity的代码是:

 DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); metrics.scaledDensity 

我做错了什么或者我误解了DisplayMetrics.scaledDensity实际上做了什么?

更新

这里有三个屏幕截图,说明了我的意思:

在此处输入图像描述

这是应用程序的代码:

 DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); String result = "\n" + "density : " + metrics.density + " (24 dp = " + 24 * metrics.density + " px)\n" + "scaledDensity: " + metrics.scaledDensity + " (24 sp = " + 24 * metrics.scaledDensity + " px)\n"; ((TextView) this.findViewById(R.id. label)).setText(result); ((TextView) this.findViewById(R.id. sp)).setTextSize(android.util.TypedValue. COMPLEX_UNIT_SP , 24); ((TextView) this.findViewById(R.id.dp )).setTextSize(android.util.TypedValue. COMPLEX_UNIT_DIP, 24); 

我希望能够计算绘制某个字符串所需的像素数量。 如果我使用dp指定字符串的大小,我可以使用displayMetrics.density轻松计算所需的像素。 但是当我使用sp并尝试使用displayMetrics.scaledDensity计算像素数量时,我没有得到正确的值。

我自己能够弄清楚这一点。 通过Android源代码挖掘后,我发现 scaledDensity属性计算为scaledDensity = density * fontScale ,其中fontScale依赖于字体大小的系统设置。 所以这就像我认为的那样。

无论字体大小如何, scaledDensity总是为我提供相同的值的原因是因为我使用DisplayMetrics来显示错误的显示 。 我从默认显示中获取了DisplayMetrics,关于此文档说:

返回此WindowManager实例将在其上创建新窗口的Display。

尽管此方法的名称,返回的显示不一定是系统的主显示(请参阅DEFAULT_DISPLAY)。 返回的显示可以是该窗口管理器实例正在管理的辅助显示。 可以将其视为此WindowManager实例默认使用的显示。

在这种情况下,默认显示与系统的主显示不同显示,因此当我更改系统字体设置时,在主显示屏上而不是在默认显示屏上更改设置。 如果我更新我的代码以获取实际使用的显示的DisplayMetricsscaledDensity将返回根据系统字体设置缩放的预期值。

使用以下更新的代码使用getResources().getDisplayMetrics()一切都按预期工作:

 DisplayMetrics metrics = getResources().getDisplayMetrics(); String result = "\n" + "density : " + metrics.density + " (24 dp = " + 24 * metrics.density + " px)\n" + "scaledDensity: " + metrics.scaledDensity + " (24 sp = " + 24 * metrics.scaledDensity + " px)\n" ; ((TextView) this.findViewById(R.id.label)).setText(result); ((TextView) this.findViewById(R.id.sp)).setTextSize(TypedValue.COMPLEX_UNIT_SP, 24); ((TextView) this.findViewById(R.id.dp)).setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24); 

通过这种获取显示指标的方式,这是我得到的结果(观察缩放密度如何随字体大小而变化):

在此处输入图像描述

缩放密度是度量单位,而不是字体大小的值。 让我试着给你一个例子,如果你想要更多的解释,请随时跟进评论。

假设您的字体大小为18sp。 这需要转换为像素才能在屏幕上显示。 进行以下计算: pixels = fontSize * scaledDensity * scale 。 现在,当您更改手机的设置时,您正在更改比例 。 这导致进行相同的计算,但是现在使用1.5而不是1的比例.scaledDensity的单位不会改变,因为屏幕的像素密度没有改变。

我希望有所帮助!