Abrufen der Bildschirmbreite auf API-Ebene 30 (Android 11): getDefaultDisplay() und getMetrics() sind jetzt veraltet. Was sollten wir stattdessen verwenden?

Lesezeit: 6 Minuten

Benutzeravatar von Denis
Dennis

Ich berechne derzeit die Bildschirmbreite wie folgt:

public static int getScreenWidth(@NonNull Context context) {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    return displayMetrics.widthPixels;
}

Da diese 2 Funktionen (getDefaultDisplay() und getMetrics()) sind jetzt veraltet, was sollten wir stattdessen verwenden?

  • Welche Größe willst du genau berechnen? Soll es Statusleisten, Navigationsleisten, Ausschnitte enthalten? Ich habe die in der Dokumentation vorgeschlagenen Ersetzungen ausprobiert und keine Kombination von Optionen gefunden, die dieselbe Höhe wie dieser Code erzeugen, was für mich darauf hindeutet, dass dieser Code wahrscheinlich keine besonders nützliche Metrik berechnet.

    –Ryan M

    14. August 2020 um 8:39 Uhr


  • context.getDisplay() ist die Alternative zu context.getWindowManager().getDefaultDisplay()

    – Jashanpreet singh Chakkal

    13. April 2021 um 4:01 Uhr

  • @JashanChakkal, aber getMetrics() von getDisplay() ist immer noch veraltet.

    – Chitgoks

    16. Oktober 2021 um 12:53 Uhr

Für die Berechnung der Bildschirmbreite abzüglich aller Systembalken sollte dies funktionieren:

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;
    }
}

Beachten Sie, dass dies nicht der Fall ist exakt dasselbe: Das Testen mit der Höhe führt zu anderen Ergebnissen, und ich war nicht in der Lage, die Funktionalität der alten API mit der neuen API zu replizieren (teilweise aufgrund des Verhaltens der alten API, das etwas schwierig zu verstehen ist und nicht immer das, was Sie tun wollen, daher seine Abwertung). In der Praxis sollte es aber als generische Bildschirmbreite für viele Dinge gut genug sein.

  • Ich habe die Dokumentation gelesen und denke auch, dass dies so sein sollte. Sie haben Recht.

    – Dennis

    14. August 2020 um 9:22 Uhr

  • Ihre neue und veraltete Methode gibt unterschiedliche Ergebnisse für Pixel 4 im Querformat zurück

    – Benutzer924

    10. Dezember 2020 um 17:43 Uhr


  • Ich denke, wir sollten auch verwenden window.decorView.rootWindowInsets?.displayCutout (safeInsetLeft und safeInsetRight), das sind nicht alle 0einige > 0

    – Benutzer924

    10. Dezember 2020 um 17:52 Uhr


  • Es gibt ein Problem bei der Verwendung von windowMetrics.getWindowInsets(), wenn der Bildschirm zwangsweise vom Hochformat ins Querformat gedreht wird, geben Insets.left und insets.right immer 0 zurück.

    – CodierungBruceLee

    27. September 2021 um 12:47 Uhr

  • und Dichte für R+?

    – Benutzer924

    24. Dezember 2021 um 10:45 Uhr

Benutzeravatar von Vincent Joshua Tigas
Vincent Joshua 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
        }
    }

Dies erfordert androidx.core Ausführung 1.5.x

  • Dein RequiresApi falsch ist, erfordert es API-Level 23.

    – Xam

    25. August 2021 um 21:22 Uhr

Wenn 2022 dasselbe Problem auftritt, gibt es eine neuere Jetpack-Bibliothek, um dies über die verschiedenen API-Versionen hinweg zu handhaben.

build.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();

Eine Einschränkung, auf die ich auch gestoßen bin, ist die einschließlich androidx.window Am Ende zog ich Zehntausende von Bibliotheksmethoden ein, die mich über das DEX 64k-Methodenlimit brachten, also musste ich herausfinden, wie diese mithilfe der R8/Proguard-Einstellungen optimiert werden, aber das ist ein anderes Problem.

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

hatas Benutzeravatar
hat

Ich denke, ich habe erfolgreich gleichwertige Methoden (Verbesserung von @RyanM) implementiert, um eine zu verwerfen.

@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;
    }
}

Die Punkte sind

  1. Die Höhe von SystemBar ist nicht in der Höhe von Windowbound enthalten. Wir sollten nur die Höhe der Navigationsleiste ausschließen (es sei denn, sie befindet sich im Querformat auf dem Telefongerät).
  2. Im Querformat auf dem Telefongerät sollten wir die Größe der Navigationsleiste von der Breite der Fensterbegrenzung ausschließen.

TESTS

1. Auf meinem echten Telefon (API-30)

Porträt:

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)

Landschaft:

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. Auf emuliertem Nexus10 (API-31)

Porträt:

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)

Landschaft:

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. Auf emuliertem Nexus7 (API-31)

Porträt:

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)

Landschaft:

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)

Benutzeravatar von Chandrakanth
Chandrakanth

Die meisten Antworten hier verwenden windowManager.getCurrentWindowMetrics() Methode, um die Bildschirmgröße zu erhalten. Dies gibt jedoch nicht die tatsächliche Bildschirmgröße (physisches Gerät) an. Wenn sich der Bildschirm im geteilten Modus befindet, nimmt die Anwendung nur einen Teil des Bildschirms ein und zeigt diese Größe anstelle der vollen Bildschirmgröße an.

Um also die Vollbildgröße zu erhalten, wird die Verwendung empfohlen windowManager.getMaximumWindowMetrics() Methode.

WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
WindowMetrics metrics = windowManager.getMaximumWindowMetrics();
Rect bounds = metrics.getBounds();
int width = bounds.width();
int height = bounds.height();

Benutzeravatar von Ravi Makwana
Ravi Makwana

Sie können verwenden

Context.getDisplay() Anstatt von getDefaultDisplay()

display.getRealMatrix(displayMetrics) Anstatt von display.getMetrics(displayMetrics)

  • display.getRealMatrix gibt die volle Größe Ihres Bildschirms zurück (einschließlich der Größe der Statusleiste und der Navigationsleiste)

    – Benutzer924

    10. Dezember 2020 um 17:20 Uhr

1432050cookie-checkAbrufen der Bildschirmbreite auf API-Ebene 30 (Android 11): getDefaultDisplay() und getMetrics() sind jetzt veraltet. Was sollten wir stattdessen verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy