Wie kann man die Bildschirmgröße von Android ein für alle Mal programmgesteuert ermitteln?

132

Wie kann ich meine Bildschirmgröße programmgesteuert in den Einheiten ermitteln, die von Berührungsereignissen verwendet werden, und Messung / Layout anzeigen? Mit anderen Worten, ich möchte die Koordinaten der unteren rechten Ecke des Bildschirms in dem Koordinatensystem, das von Berührungsereignissen getRawX()/getRawY()und verwendet wird View.getLocationOnScreen().

Ich zögere, die gewünschten Ereignis- / Ansichtseinheiten als "Pixel" zu bezeichnen, da auf meinem Telefon offensichtlich mehrere Begriffe von "Pixeln" in verschiedenen Modi vorhanden sind, die nicht zu einer konsistenten Geschichte führen.

Ich sehe, dass dies im Stackoverflow und anderswo häufig gefragt und beantwortet wurde, aber keine der Antworten funktioniert tatsächlich auf meinem Telefon (Droide 4, Android 4.1.2) in allen Modi:

(Beeindruckend!)

Dies gilt für Bibliothekscode, der unabhängig davon funktionieren muss, ob sich die App im "Bildschirmkompatibilitätsmodus" befindet (dh targetSdkVersion <= 10 im Manifest) oder nicht, und ich möchte auch keine Annahmen über Position und Größe treffen oder das Vorhandensein der Statusleiste oder anderer ähnlicher Bildschirmdekorationen.


Hier sind die Fakten:

  1. Mein Telefon (ein Droide 4 mit Android 4.1.2) hat 540 x 960 physische Pixel, dh kleine farbige leuchtende Punkte.

  2. Die Größe des Bildschirms in den gewünschten Einheiten beträgt 360 x 640, wenn sich die App im Bildschirmkompatibilitätsmodus befindet, 540 x 960, wenn sich die App nicht im Bildschirmkompatibilitätsmodus befindet. Dies sind die Zahlen, die ich programmgesteuert finden muss, ohne mich mit Berührungsereignissen oder Ansichten zu beschäftigen, um sie zu finden, aber ich habe extreme Schwierigkeiten, eine API zu finden, die diese Zahlen zurückgibt.

  3. Alle auf verschiedene Weise erhaltenen Display- und DisplayMetrics-Objekte geben an, dass die Bildschirmgröße 540 x 960 "Pixel" beträgt (unabhängig davon, ob sie im Bildschirmkompatibilitätsmodus vorliegen oder nicht). Um genau zu sein, sagen die folgenden immer 540 x 960: DisplayMetrics. {Breite, Höhe} Pixel, Display.getSize (), Display.getRealSize (), Display.get {Breite, Höhe} (),

  4. Auf verschiedene Weise erhaltene Konfigurationsobjekte sagen alle Bildschirm {Breite, Höhe} Dp = 360x614 (ob im Bildschirmkompatibilitätsmodus oder nicht). Ich glaube nicht, dass dies den gesamten Bildschirm darstellt, da das Seitenverhältnis falsch ist. (Ich denke, es ist der gesamte Bildschirm abzüglich der Statusleiste; ich brauche den gesamten Bildschirm.) Ich kann mit Sicherheit sagen, dass der gesamte Bildschirm 360 x 640 dp groß ist, obwohl ich keine API kenne, die diese 640 zurückgibt.

  5. Auf verschiedene Weise erhaltene DisplayMetrics besagen, dass die "Dichte" im bildschirmkompatiblen Modus 1,0 f und im nicht bildschirmkompatiblen Modus 1,5 f beträgt.

  6. Die Aktivität getWindow().getAttributes().{width,height} ist nicht hilfreich, da sie normalerweise MATCH_PARENT eher als tatsächliche Größen enthält. Aber ich kann anscheinend die gewünschte Antwort von einer Aktivität erhalten getWindow().getDecorView().getMeasured{Width,Height}() (was tatsächlich überraschend ist, da die decorView des Aktivitätsfensters nicht so aussieht, als würde sie den gesamten Bildschirm einnehmen; es sieht so aus, als würde sie den Bildschirm abzüglich der Statusleiste einnehmen). Aber ich möchte mich nicht darauf verlassen, denn wenn die Größe des Fensters jemals geändert wird (eine weiche Tastatur wird angezeigt? Jemand, der window.setAttributes () aufruft? Oder ich bin überhaupt nicht in einer Aktivität), wird dies eindeutig alles sein falsch.

Ich verstehe, dass die folgende Formel gelten soll: Pixel = dp * Dichte Dies scheint mit allen oben angegebenen Zahlen ((3), (4), (5)) übereinzustimmen, wenn Sie sich nicht im Bildschirmkompatibilitätsmodus befinden: 540x960 = 360x640 * 1,5 Im Bildschirmkompatibilitätsmodus summiert sich dies jedoch nicht: 540 x 960! = 360 x 640 * 1 Es stimmt also etwas nicht.

Ich denke, die einfachste Erklärung ist, dass die in (3) oben aufgeführten Methoden im Bildschirmkompatibilitätsmodus einfach die falsche Antwort für "Pixel" geben - das heißt, sie sollten 360 x 640 "Pixel" zurückgeben, aber sie sind falsch stattdessen 540x960 zurückgeben. Es kann aber auch andere Sichtweisen geben.

In jedem Fall ist es sicherlich schwierig, die gewünschten Zahlen unabhängig vom Modus aus den oben genannten Puzzleteilen zu erhalten. Ich habe einen Weg gefunden, der auf meinem Telefon in beiden Modi zu funktionieren scheint, aber er ist äußerst umständlich und basiert auf zwei Annahmen, die immer noch ziemlich wackelig erscheinen (wie in den folgenden Codekommentaren beschrieben).

Hier ist mein Rezept:

/** get screen size in "pixels", i.e. touchevent/view units.
* on my droid 4, this is 360x640 or 540x960
* depending on whether the app is in screen compatibility mode
* (i.e. targetSdkVersion<=10 in the manifest) or not. */
public void getScreenSizePixels(int widthHeightInPixels[/*2*/])
{
    Resources resources = getResources();
    Configuration config = resources.getConfiguration();
    DisplayMetrics dm = resources.getDisplayMetrics();
    // Note, screenHeightDp isn't reliable
    // (it seems to be too small by the height of the status bar),
    // but we assume screenWidthDp is reliable.
    // Note also, dm.widthPixels,dm.heightPixels aren't reliably pixels
    // (they get confused when in screen compatibility mode, it seems),
    // but we assume their ratio is correct.
    double screenWidthInPixels = (double)config.screenWidthDp * dm.density;
    double screenHeightInPixels = screenWidthInPixels * dm.heightPixels / dm.widthPixels;
    widthHeightInPixels[0] = (int)(screenWidthInPixels + .5);
    widthHeightInPixels[1] = (int)(screenHeightInPixels + .5);
}

Gibt es eine bessere / sauberere Möglichkeit, die Größe des Bildschirms zu ermitteln?

Don Hatch
quelle
29
+1 Gute Frage und zeigt viel Forschungsaufwand.
Alex Gittemeier
1
@Don In den Dokumenten wird erklärt, dass der Kompatibilitätsmodus bei älteren Setups nicht mehr "Zoom to Fit" ausführt. Aus Ihren Beobachtungen geht jedoch nicht klar hervor, wie es funktioniert. Ich denke, sie deaktivieren einfach die Dichteskalierung, dh: 1px wird zu 1dp. Es kann sein, dass diese Änderung nur im Rendering-Teil enthalten ist und DisplayMetricsniemals über solche Änderungen aktualisiert wird. Es gibt Probleme wie diese bereits eingereicht.
SD
@ user117 - interessant. Nun, ein Teil von DisplayMetrics wurde mindestens aktualisiert - die Dichte wurde auf 1,0 geändert. Aber widthPixels / heightPixels wurden anscheinend nicht entsprechend geändert. Die Frage in Bezug auf zitiert, es sieht aus wie das Verhalten auf das 3.1 Verhalten zurückgesetzt (dh ich sehe heightPixels umfasst die Statusleiste ... aber in den falschen Einheiten wie es scheint)
Don Hatch
@DonHatch Danke, freundlicherweise - ich habe tatsächlich versucht, eine nachdenkliche Frage zu loben, die bei StackExchange seltsamerweise nicht so willkommen ist - beachten Sie, dass die Frage, die mehr als "echt" ist, nichts in den Antworten enthält, wenn man von (niedrig) spricht ) Qualität des Publikumswissens zum Thema. Jetzt mag ich traumatisiert sein, wenn meine eigenen Fragen nacheinander geschlossen werden, weil sie "nicht real" sind, und der Sinn für Humor versagt mir vielleicht, aber es sieht aus wie Fragen, auf die es wirklich "nette" Antworten gibt Worum geht es hier hier? Und natürlich habe ich deine
positiv
Übrigens! Hier ist etwas in der Art meines Verdachts: michael.richter.name/blogs/… (siehe insbesondere seinen (1) Punkt, den über schnell gestaltete Antworten - eigentlich nur der Fall mit diesem Q!). Happy NY jedenfalls (meins kommt in 11 Minuten)! :)
mlvljr

Antworten:

41
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;

Jetzt können Sie Ihre Bildschirmgröße in Pixel messen, was eine bessere Maßeinheit als Zentimeter ist, da alle Schaltflächen, Textansichten usw. in dieser Einheit gemessen werden. Das was ich normalerweise benutze

Cobra47
quelle
3
Wäre dies laut Op (speziell Punkt 3) im Bildschirmkompatibilitätsmodus nicht falsch?
Tom
9

Mit DisplayMetrics können Sie die Höhe und Breite des Bildschirms jedes Geräts ermitteln. Beachten Sie, dass Breite und Höhe drehempfindlich sind. Hier ist der Code.

DisplayMetrics metrics; 
int width = 0, height = 0;

In Ihrer onCreate-Methode

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

 height = Math.min(metrics.widthPixels, metrics.heightPixels); //height
 width = Math.max(metrics.widthPixels, metrics.heightPixels); //width

Versuche dies.

Preet_Android
quelle
2
Nein, wie ich in (3) sagte, Metriken. {Breite, Höhe} Pixel geben im Bildschirmkompatibilitätsmodus nicht die richtige Antwort.
Don Hatch
Außerdem habe ich festgestellt: Es scheint, als ob Lite-Metriken. HeightPixels geben möglicherweise die Breite an, falls der Bildschirm gedreht wird und umgekehrt!
JohnyTex
8

In Ihrer Nr. 6 stellen Sie fest, dass DecorView das zu bieten scheint, was Sie möchten, aber Sie glauben nicht, dass es realisierbar ist. Ich glaube, das ist so nah wie möglich. Gemäß der Dokumentation für Window.getDecorView:

Rufen Sie die Fensterdekoransicht der obersten Ebene ab (die den Standardfensterrahmen / die Standarddekorationen und den darin enthaltenen Clientinhalt enthält), die dem Fenstermanager als Fenster hinzugefügt werden kann.

Die Statusleiste ist Teil der dort genannten Fensterdekoration. Software-Tastaturen und andere Overlays erhalten ein eigenes Fenster, sodass sie die relevanten Werte nicht beeinträchtigen sollten. Es ist richtig, dass dies nicht genau die Anzeigemetriken sind. Wenn Ihre Anwendung jedoch im Vollbildmodus angezeigt wird, sollte immer die Vollbildgröße angezeigt werden, die durch den Kompatibilitätsübersetzer gefiltert wird. Andere Anwendungen haben keinen Zugriff auf Ihre Anwendungen Window, sodass Sie sich keine Sorgen machen müssen, dass eine andere App die Attribute ändert, während Sie nicht suchen.

Hoffentlich hilft das.

Dave
quelle
5

Ich sollte dies als Kommentar setzen, aber ich habe nicht den Repräsentanten dafür.
Dies ist möglicherweise keine völlig richtige Antwort, aber ich habe meine Abmessungen erhalten, als ich die Höhe und Breite in der DisplayMetrics-Methode geändert habe.

    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);   
    width = metrics.heightPixels;
    height = metrics.widthPixels;

Wie gesagt, das ist vielleicht nicht richtig, aber ich weiß nicht warum, aber es hat bei mir funktioniert.

abhyudayasrinet
quelle
Das liegt daran, dass sich Ihr Bildschirm gedreht hat, glaube ich.
JohnyTex
Es hat mir nicht vertraut.
Abhyudayasrinet
3

Wenn Sie API Level 17 oder höher verwenden, überprüfen Sie getRealMetrics und getRealSize in Display

Für API Level 14,15 & 16 schauen Sie hier

Exoit
quelle
3

Ich habe den Satz von Pythagoras verwendet, um die diagonale Größe des Android-Telefon- / Tablet-Bildschirms zu ermitteln. Das gleiche Prinzip kann auf den iPhone- oder Blackberry-Bildschirm angewendet werden.

DisplayMetrics met = new DisplayMetrics();                
this.getWindowManager().getDefaultDisplay().getMetrics(met);// get display metrics object
String strSize = 
new DecimalFormat("##.##").format(Math.sqrt(((met.widthPixels / met.xdpi) *
(met.widthPixels / met.xdpi)) +
((met.heightPixels / met.ydpi) * (met.heightPixels / met.ydpi))));
// using Dots per inches with width and height

Pythagoras muss ein Genie gewesen sein, er kannte die Smartphone-Programmierung vor so vielen Jahren: p

Naeem A. Malik
quelle
1

Ich verwende die folgende Methode, um die Breite des Geräts zu ermitteln:

public static int getDeviceWidth(Context context){
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    int width=display.getWidth();
    return width;
}
Ghanshyam Patidar
quelle
Diese Methode ist veraltet. Bitte verwenden Sie die Displaymetrics-Methode.
Simon
0

Ich denke, diese Funktion wird Ihnen helfen, einfach die Breite und Höhe Ihrer Android-Bildschirmgröße zu ermitteln. Die Funktion gibt die Breite und Höhe als Array von Ganzzahlen zurück, wie unten gezeigt

private int[] getScreenSIze(){
        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        int h = displaymetrics.heightPixels;
        int w = displaymetrics.widthPixels;

        int[] size={w,h};
        return size;

    }

und geben Sie bei Ihrer Erstellungsmethode Ihre Breite und Höhe wie unten gezeigt aus

 int[] screenSize= getScreenSIze();
        int width=screenSize[0];
        int height=screenSize[1];
        screenSizes.setText("Phone Screen sizes \n\n  width = "+width+" \n Height = "+height);

Laden Sie den Quellcode herunter und testen Sie ihn auf Ihrem Android Studio

Daniel Nyamasyo
quelle
0

Das funktioniert bei mir:

int width = Resources.getSystem (). getDisplayMetrics (). widthPixels;

int height = Resources.getSystem (). getDisplayMetrics (). heightPixels;

Ich habe dies verwendet, um die Breite meiner Artikel in einer horizontalen Recycler-Ansicht zu aktualisieren. (Entsprechend meiner Anforderung) Ich hoffe, es hilft jemandem!

Gagan Deep
quelle
-1

Versuchen Sie für diese Lösung in Kotlin Folgendes:

private fun yourFunction(){
   val metrics = DisplayMetrics()
   windowManager.defaultDisplay.getMetrics(metrics)
   val width = metrics.widthPixels
   val height = metrics.heightPixels
}
Sup.Ia.
quelle