Denis
Actualmente calculo el ancho de la pantalla así:
public static int getScreenWidth(@NonNull Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
Dado que estas 2 funciones (getDefaultDisplay() y getMetrics()) ahora están en desuso, ¿qué deberíamos usar en su lugar?
Para calcular el ancho de la pantalla menos las barras del sistema, esto debería funcionar:
public static int getScreenWidth(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();
Insets insets = windowMetrics.getWindowInsets()
.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
return windowMetrics.getBounds().width() - insets.left - insets.right;
} else {
DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
}
Tenga en cuenta que esto no es exactamente lo mismo: probar esto con la altura produce resultados diferentes, y no he podido replicar la funcionalidad de la API anterior con la API nueva (en parte debido a que el comportamiento de la API anterior es un poco complicado de razonar y no siempre lo que usted quiere, de ahí su desaprobación). Sin embargo, en la práctica, debería ser lo suficientemente bueno como un ancho de pantalla genérico para muchas cosas.
-
Estaba leyendo la documentación y también creo que así es como debería hacerse. Tienes razón.
– Denis
14 de agosto de 2020 a las 9:22
-
su método nuevo y obsoleto arroja resultados diferentes para el píxel 4 en orientación horizontal
– usuario924
10 de diciembre de 2020 a las 17:43
-
Supongo que también deberíamos usar
window.decorView.rootWindowInsets?.displayCutout
(safeInsetLeft
ysafeInsetRight
), esos no son todos0
algunos > 0– usuario924
10 de diciembre de 2020 a las 17:52
-
Hay un problema cuando se usa windowMetrics.getWindowInsets(), cuando la pantalla gira a la fuerza de vertical a horizontal, Insets.left e insets.right devuelven siempre 0.
– CodificaciónBruceLee
27 de septiembre de 2021 a las 12:47
-
y densidad para R+?
– usuario924
24 de diciembre de 2021 a las 10:45
Vicente Josué Tigas
@RequiresApi(20)
inline val Fragment.windowHeight: Int
get() {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val metrics = requireActivity().windowManager.currentWindowMetrics
val insets = metrics.windowInsets.getInsets(WindowInsets.Type.systemBars())
metrics.bounds.height() - insets.bottom - insets.top
} else {
val view = requireActivity().window.decorView
val insets = WindowInsetsCompat.toWindowInsetsCompat(view.rootWindowInsets, view).getInsets(WindowInsetsCompat.Type.systemBars())
resources.displayMetrics.heightPixels - insets.bottom - insets.top
}
}
@RequiresApi(20)
inline val Fragment.windowWidth: Int
get() {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val metrics = requireActivity().windowManager.currentWindowMetrics
val insets = metrics.windowInsets.getInsets(WindowInsets.Type.systemBars())
metrics.bounds.width() - insets.left - insets.right
} else {
val view = requireActivity().window.decorView
val insets = WindowInsetsCompat.toWindowInsetsCompat(view.rootWindowInsets, view).getInsets(WindowInsetsCompat.Type.systemBars())
resources.displayMetrics.widthPixels - insets.left - insets.right
}
}
Esto requiere androidx.core
versión 1.5.x
-
Su
RequiresApi
está mal, requiere API nivel 23.– Xam
25 de agosto de 2021 a las 21:22
Al encontrarse con el mismo problema en 2022, hay una biblioteca Jetpack más nueva para manejar esto en las diversas versiones de API.
construir.gradle
dependencies {
implementation 'androidx.window:window:1.0.0'
}
import androidx.window.layout.WindowMetrics;
import androidx.window.layout.WindowMetricsCalculator;
WindowMetrics windowMetrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity);
final int height = windowMetrics.getBounds().height();
final int width = windowMetrics.getBounds().width();
Una advertencia con la que me encontré también es que incluir androidx.window
terminé obteniendo decenas de miles de métodos de biblioteca que me colocaron por encima del límite de método DEX 64k, así que tuve que descubrir cómo optimizarlos usando la configuración de R8/proguard, pero ese es otro problema.
hata
Supongo que he implementado con éxito métodos equivalentes (mejorando los de @RyanM) para uno obsoleto.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Deprecated older method for comparison.
DisplayMetrics outMetrics = new DisplayMetrics();
getDisplay().getMetrics(outMetrics);
Log.d("Upto API-29", String.format(
"(width, height) = (%d, %d)", outMetrics.widthPixels, outMetrics.heightPixels
));
// Newer methods.
Log.d("API-30+", String.format(
"(width, height) = (%d, %d)", getScreenWidth(this), getScreenHeight(this)
));
}
public static int getScreenWidth(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();
Rect bounds = windowMetrics.getBounds();
Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars()
);
if (activity.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE
&& activity.getResources().getConfiguration().smallestScreenWidthDp < 600
) { // landscape and phone
int navigationBarSize = insets.right + insets.left;
return bounds.width() - navigationBarSize;
} else { // portrait or tablet
return bounds.width();
}
} else {
DisplayMetrics outMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
}
public static int getScreenHeight(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();
Rect bounds = windowMetrics.getBounds();
Insets insets = windowMetrics.getWindowInsets().getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars()
);
if (activity.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE
&& activity.getResources().getConfiguration().smallestScreenWidthDp < 600
) { // landscape and phone
return bounds.height();
} else { // portrait or tablet
int navigationBarSize = insets.bottom;
return bounds.height() - navigationBarSize;
}
} else {
DisplayMetrics outMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
}
los puntos son
- La altura de SystemBar no está incluida en la altura del límite de la ventana. Deberíamos excluir solo la altura de la barra de navegación (a menos que esté en modo horizontal en el dispositivo del teléfono).
- En modo horizontal en el dispositivo del teléfono, debemos excluir el tamaño de la barra de navegación del ancho del límite de la ventana.
PRUEBAS
1. En mi teléfono real (API-30)
retrato:
2021-12-14 22:17:28.231 31660-31660/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (1080, 2016)
2021-12-14 22:17:28.237 31660-31660/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (1080, 2016)
paisaje:
2021-12-14 22:17:35.858 31660-31660/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (2016, 1080)
2021-12-14 22:17:35.887 31660-31660/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (2016, 1080)
2. En Nexus10 emulado (API-31)
retrato:
2021-12-14 22:19:33.379 1416-1416/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (1600, 2464)
2021-12-14 22:19:33.382 1416-1416/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (1600, 2464)
paisaje:
2021-12-14 22:18:44.809 1416-1416/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (2560, 1504)
2021-12-14 22:18:44.814 1416-1416/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (2560, 1504)
2. En Nexus7 emulado (API-31)
retrato:
2021-12-14 22:21:21.606 3108-3108/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (800, 1216)
2021-12-14 22:21:21.610 3108-3108/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (800, 1216)
paisaje:
2021-12-14 22:22:23.283 3108-3108/com.stackoverflow.windowmetrics D/Upto API-29: (width, height) = (1280, 736)
2021-12-14 22:22:23.289 3108-3108/com.stackoverflow.windowmetrics D/API-30+: (width, height) = (1280, 736)
val windowMetrics = requireActivity().windowManager.currentWindowMetrics
val displayMetrics = resources.displayMetrics
val pxHeight = windowMetrics.bounds.height()
val pxWidth = windowMetrics.bounds.width()
val density = displayMetrics.density
val dpHeight = pxHeight/density
val dpWidth = pxWidth/density
Ravi Makwana
Puedes usar
Context.getDisplay()
en vez de getDefaultDisplay()
display.getRealMatrix(displayMetrics)
en vez de display.getMetrics(displayMetrics)
¿Qué tamaño, exactamente, estás tratando de calcular? ¿Debería incluir barras de estado, barras de navegación, recortes? He estado probando los reemplazos sugeridos en la documentación y no he podido encontrar ninguna combinación de opciones que produzca la misma altura que este código, lo que me sugiere que este código probablemente no esté calculando una métrica particularmente útil.
– Ryan M.
♦
14 de agosto de 2020 a las 8:39
context.getDisplay() es la alternativa en lugar de context.getWindowManager().getDefaultDisplay()
– Jashan Chakkal
13 de abril de 2021 a las 4:01
@JashanChakkal pero getMetrics() de getDisplay() todavía está en desuso.
– Chitgoks
16 oct 2021 a las 12:53