Höhe der Statusleiste?

70

Gibt es eine Möglichkeit, die Höhe der Statusleiste + Titelleiste zu ermitteln? Das Überprüfen des Entwicklerforums zeigt die gleiche Frage, aber keine Lösung (die ich finden konnte).

Ich weiß, dass wir es nach dem ersten Layout-Durchlauf erhalten können, aber ich möchte es in onCreate () meiner Aktivität erhalten.

Vielen Dank

user291701
quelle
Hallo, ich habe mich gefragt, warum du diese Höhe erreichen willst.
Jorgesys
Ich muss die Größe einer in dieser Aktivität gehosteten Webansicht auf die verfügbare Höhe einstellen (minus Titelleiste / Statusleiste). Danke
user291701
Das material.io gibt die Antwort. > Metriken:> Android Statusleiste Höhe: 24dp> Chrome Fensterhöhe: 32dp material.io/guidelines/layout/…
cong

Antworten:

102
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop= 
    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;

   Log.i("*** Jorgesys :: ", "StatusBar Height= " + StatusBarHeight + " , TitleBar Height = " + TitleBarHeight); 

onCreate()Verwenden Sie diese Methode, um die Höhe der Statusleiste für die Methode Ihrer Aktivität abzurufen:

public int getStatusBarHeight() { 
      int result = 0;
      int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
      if (resourceId > 0) {
          result = getResources().getDimensionPixelSize(resourceId);
      } 
      return result;
} 
Jorgesys
quelle
10
Dies setzt eine wichtige Annahme voraus, dass sich die Statusleiste oben befindet. Ich würde erwarten, dass dies immer der Fall ist.
Hackbod
Sie sollten es in einem verzögerten Rückruf oder nach der onCreate-Methode aufrufen, bei der die Größen bereits gemessen werden.
Roger Alien
Wie @hackbod erwähnt hat dies voraus, dass sich die Statusleiste oben befindet, und wenn wir die Systemleiste für Android-Tablets unten betrachten, schlägt dies fehl (könnte aber leicht an die Bildschirmhöhe angepasst werden - Fenster unten.
Tom
1
@ Tom: Ich habe die Erfahrung gemacht, dass wenn sich die Systemleiste (Navi oder kombiniert) unten befindet, dieser Betrag aus der Gesamthöhe der von DisplayMetrics gemeldeten Anzeige herausgeschnitten wird, sodass Ihre App den Eindruck erweckt, dass sie eine kleinere hat verfügbarer Platz zum Zeichnen. Dies ist eine App, die auf API 8 abzielt. Wenn Sie also auf etwas Höheres abzielen (z. B. Honeycomb, wo Nav oder kombinierte Balken zum ersten Mal verwendet wurden), YMMV. Wenn der Grund dafür, dass Sie die Höhe der Statusleiste benötigen, darin besteht, sie vom verfügbaren Platz abzuziehen, müssen Sie diesen Abzug möglicherweise nicht für den NAV oder die kombinierte Leiste unten vornehmen.
Carl
Kann jemand bitte auch das XML-Gegenstück angeben? Ein bisschen wie die folgenden für Actionbar Größe: "?attr/actionBarSize"
Pier Betos
40

Für diejenigen wie mich, die es in Ihren XML-Layouts verwenden möchten:

<...
  android:layout_marginTop="@*android:dimen/status_bar_height"
  ... />

Lassen Sie sich nicht verwirren, dass Android Studio (2.2 Vorschau 3 - zum Zeitpunkt des Schreibens) diesen Gedanken nicht unterstützt. Die Laufzeit tut. Ich habe es dem Quellcode von Google entnommen.

Aleksey Gureiev
quelle
13
Fehler: (30, 43) Ressource ist nicht öffentlich. (bei 'layout_marginTop' mit dem Wert '@android: dimen / status_bar_height').
Khan
4
@ Khan Vergiss den Stern nicht (*). Es ist @ * android: dimen / status_bar_height
Kabir
7
Bitte, können Sie erklären, was @ * Android-Notation bedeutet. danke
GPack
3
Funktioniert gut bis API 24, stürzt auf API 25 (Android 7.1.1) ab. Es wird Ihnen der Fehler angezeigt, You must supply a layout_height(width) attributewenn Sie ihn für Layoutdateien verwenden.
ntcho
4
Auf dem API 21-Emulator stürzt es mit "Verursacht durch: java.lang.UnsupportedOperationException: Kann nicht in Dimension konvertieren: Typ = 0x1" ab.
CoolMind
39

Obwohl dies eine alte Frage ist, stellte ich fest, dass die Antwort nicht funktionierte in onCreate():

Ich habe diesen Code von hier gefunden, der in der onCreate()Methode funktioniert

public int getStatusBarHeight() {
   int result = 0;
   int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
   if (resourceId > 0) {
      result = getResources().getDimensionPixelSize(resourceId);
   }
   return result;
}

Ich hoffe, dies hilft jedem, der auf dieses Problem stößt.

Raukodraug
quelle
Ich habe diesen Code verwendet, als ich ein Live-Hintergrundbild erstellt habe. Ich konnte keine Aktivitäten finden window, daher war diese Funktion für mich nützlich!
Nolesh
10

Die unterstützte Methode zum WindowInsetsAbrufen der Statusleistenhöhe besteht darin, eine Klasse ab API 21+ zu verwenden:

customView.setOnApplyWindowInsetsListener((view, insets) -> {
    // Handle insets
    return insets.consumeSystemWindowInsets();
});

oder WindowInsetsCompatfür Support-Bibliotheken:

ViewCompat.setOnApplyWindowInsetsListener(customView, (view, insets) -> {
    // Handle insets
    return insets.consumeSystemWindowInsets();
});

Sie können die onApplyWindowInsetsMethode auch in der Ansicht überschreiben :

public class CustomView extends View {
    @Override
    public WindowInsets onApplyWindowInsets(final WindowInsets insets) {
        final int statusBarHeight = insets.getStableInsetTop();
        return insets.consumeStableInsets();
    }
}

Für weitere Details würde ich empfehlen, Chris Banes Vortrag zu überprüfen - Werden Sie ein Master-Fensterbauer (Folien hier verfügbar ).

yarq
quelle
@CoolMind Könnten Sie bitte mitteilen, auf welchen APIs es nicht funktioniert, diese Lösung zu überprüfen?
Yarq
Ich habe auf einem Emulator mit API 19, 21, 23 getestet. Wahrscheinlich irre ich mich, sorry.
CoolMind
1
Der Aufruf von insets.consumeStableInsets () hat Nebenwirkungen. Rufen Sie besser einfach view.onApplyWindowInsets auf, das an das ursprüngliche Fenster zurück delegiert, um sich mit Insets zu befassen.
Robin Davies
7

Ich würde nächsten Code vorschlagen:

Rect rect = new Rect();
Window window = activity.getWindow();
if (window != null) {
  window.getDecorView().getWindowVisibleDisplayFrame(rect);
  android.view.View v = window.findViewById(Window.ID_ANDROID_CONTENT);

  android.view.Display display = ((android.view.WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

  //return result title bar height
  return display.getHeight() - v.getBottom() + rect.top;   
}

Zwei Beispiele:

1) Gerät 1 Marke: Samsung, Gerät: Maguro, Board: Thunfisch, CPU_ABI: Armeabi-V7A, Anzeige: ICL53F.M420KREL08, Hersteller: Samsung, Modell: Galaxy Nexus, Version: 4.0.2, Version: 14 ;;

Bildschirmauflösung: 1280 x 720. Auf diesem Gerät befinden sich keine Hardwaretasten.

Ergebnisse:

rect: left=0 right=720 top=72 bottom=1208;
v: left=0 right=720 top=72 bottom=1208;
display: height=1208 width=720;
correct result=72;

Gerät 1 verfügt über eine Titelleiste am oberen Bildschirmrand und eine Statusleiste mit Softwaretasten am unteren Bildschirmrand.

2) Gerät 2 Gerät: bravo, Board: bravo, cpu_abi: armeabi-v7a, Anzeige: FRG83G, Hersteller: HTC, Modell: HTC Desire, Version: 2.2.2, Version: 8,

Bildschirmauflösung: 800 x 400. Dieses Gerät verfügt über Hardwaretasten.

Ergebnisse:

rect: left=0 right=480 top=38 bottom=800;
v: left=0 right=480 top=0 bottom=800;
display: height=800 width=480;
correct result: phone_bar_height=38;

Gerät 2 hat eine Titelleiste am oberen Bildschirmrand und überhaupt keine Statusleiste.

Oben wurden zwei Lösungen vorgeschlagen:

A) v.getTop() - rect.top 

( es ist falsch für Gerät 1 - es gibt 0 statt 72)

B) display.getHeight() - v.getHeight() 

( es ist falsch für Gerät 2 - es gibt 0 statt 38)

Variante:

 display.getHeight() - v.getBottom() + rect.top

gibt in beiden Fällen korrekte Ergebnisse.

Aktualisieren

3) Ein weiteres Beispiel (drittes Gerät): Marke: LGE, Gerät: v909, cpu_abi: armeabi-v7a, Anzeige: HMJ37, Modell: LG-V909, Version: 3.1, Version: 12

rect: left=0 right=1280 top=0 bottom=720
v: left=0 right=1280 top=0 bottom=720
Display: height=768 width=1280
phone_bar_height=48

Gerät 3 hat eine horizontale Ausrichtung, keine Titelleiste am oberen Bildschirmrand und eine Statusleiste am unteren Bildschirmrand.

Also hier:

int size_of_title_bar = rect.top;
int size_of_status_bar = display.getHeight() - v.getBottom();

Es ist für die Geräte 2 und 3 korrekt. Ich bin mir bei Gerät 1 nicht sicher. Der Benutzer hat mir einen Screenshot von Gerät 1 gesendet. Dort befindet sich eine Statusleiste mit der Softwaretaste. Der Ausdruck "display.getHeight () - v.getBottom ()" ergibt jedoch 0.

dvpublic
quelle
6

Sie können auch die Dimension der Statusleiste in der Datei dimension.xml von Android auf die in diesem Blogbeitrag beschriebene Weise übernehmen.

Dadurch kann die Höhe der Statusleiste ermittelt werden, ohne auf das Zeichnen warten zu müssen.

Zitieren des Codes aus dem Blog-Beitrag:

public int getStatusBarHeight() {
  int result = 0;
  int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
  if (resourceId > 0) {
      result = getResources().getDimensionPixelSize(resourceId);
  }
  return result;
}

Sie müssen diese Methode in eine ContextWrapper-Klasse einfügen.

LKallipo
quelle
Es ist Jahre her, aber ich habe das Snippet trotzdem hinzugefügt, da der Link zum Glück noch am Leben ist
LKallipo
4

Hängen Sie eine ausführbare Datei an eine Ihrer Ansichten in Ihrer onCreate-Methode an und platzieren Sie den obigen Code dort. Dadurch berechnet die Anwendung die Statusleiste und die Höhe des Titelbildschirms, wenn sie an den Bildschirm angehängt werden.

Schauen Sie sich den folgenden Code an:

myView.post(new Runnable() {

        @Override
        public void run() {
            Rect rectgle= new Rect();
            Window window= getWindow();
            window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
            int StatusBarHeight= rectgle.top;
            int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
            int TitleBarHeight= contentViewTop - StatusBarHeight;

        }

    });

Wenn dies immer noch nicht ausreicht, rufen Sie die postDelayed-Methode der Ansicht anstelle von post auf und fügen Sie als zweites Argument einen Millisekundenwert hinzu.

Kachi
quelle
Erklären Sie, warum dies sicher ist?
Tomwhipple
(Eingabetaste hat mich abgeschnitten ...) Die Dokumente, die ich sehe ( developer.android.com/reference/java/lang/Runnable.html ), legen nahe, dass dies einen eigenen Thread startet. Nach meinem Verständnis ist die Interaktion mit der Benutzeroberfläche im Allgemeinen nicht threadsicher, und selbst wenn dies der Fall wäre, ist der Leistungsaufwand für etwas Einfaches wie das Abrufen der Statusleistenhöhe sehr hoch.
Tomwhipple
Dadurch wird kein neuer Thread gestartet, sondern der Runnable wird zur Nachrichtenwarteschlange im UI-Thread hinzugefügt. Schauen Sie sich die Dokumentation zur Post-Methode in der View-Klasse an. Es wird dort erklärt. developer.android.com/reference/android/view/…
Kachi
@Felix Ich weiß, dass die Verwendung von View.post () wie gesagt funktioniert (ich verwende es selbst, um die Höhe einer Ansicht zur Laufzeit in onCreate () zu ermitteln). Aber ich habe die Mechanik dahinter nie ganz verstanden. Das view, auf dem Sie post () aufrufen, ist willkürlich korrekt? Egal welche viewSie verwenden, Runnablewird in dieselbe UI-Thread-Nachrichtenwarteschlange gestellt? Ich weiß, dass es funktioniert, aber wird jemals irgendwo erklärt, dass die posted runnable / message erst ausgeführt wird, nachdem die views gemessen und layout () abgeschlossen wurden?
Tony Chan
1

Ich denke, ein besserer Weg, dies zu berechnen, besteht darin, die Höhe des Vollbilds abzüglich unseres Hauptlayouts zu ermitteln

phoneBarsHeight = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight() 
    - mainView.getHeight();

Und du kannst es hineinstecken onGlobalLayout(). Dies funktioniert auch auf Tablets, ich habe es auf Theme.NoTitleBar versucht, aber es muss immer funktionieren.

Vielleicht können Sie es sogar es verbessern und verwenden , onCreate()indem Sie mainView.getHeight()auf mainView.getMeasuredHeight().

Mikooos
quelle
getMeasuredHeight () gibt im onCreate leider 0 zurück.
Ben Clayton
Es kann von der Plattform abhängen. Verwenden Sie diese
Option
1
OnCreate ist zu früh. Sie können getMeasuredHeight für eine Ansicht in onResume aufrufen. Dies ist der Rückruf, bis zu dem Ihre Ansichten sichtbar sein sollten.
Speedynomads
1

Die von Jorgesys veröffentlichte Lösung ist sehr gut, funktioniert jedoch nicht in der onCreate () -Methode. Ich denke, das liegt daran, dass Statusleiste und Titelleiste nach onCreate () erstellt werden.

Die Lösung ist einfach: Sie sollten Code in runnable einfügen und ihn nach onCreate () mit using ausführen root.post((Runnable action) );

Also die ganze Lösung:

root = (ViewGroup)findViewById(R.id.root);
root.post(new Runnable() { 
        public void run(){
            Rect rectgle= new Rect();
            Window window= getWindow();
            window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
            int StatusBarHeight= rectgle.top;
            int contentViewTop= 
                 window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
            int TitleBarHeight= contentViewTop - StatusBarHeight;

            Log.i("***  jakkubu :: ", "StatusBar Height= " + StatusBarHeight +
               " , TitleBar Height = " + TitleBarHeight);
        }
});

Ich finde es hier

Jakkubu
quelle
1

Ab API 23 gibt es eine bessere Lösung, um die Höhe der Statusleiste zu ermitteln. API 23 fügt eine WindowInsetsFunktion hinzu, sodass Sie diesen Code verwenden können, um die Größe der Systemeinfügungen zu ermitteln, in diesem Fall oben.

public int getStatusBarHeight() {
    if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        return binding.mainContent.getRootWindowInsets().getStableInsetTop();
    }
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if(resourceId != 0) {
        return getResources().getDimensionPixelSize(resourceId);
    }
    return 0;
}

Beachten Sie, dass getRootWindowInsets()null zurückgegeben wird, bis die Ansicht an ein Fenster angehängt wurde, sodass sie nicht direkt in verwendet werden onCreate()kann. Sie können jedoch einen Listener für das Anhängen des Fensters hinzufügen und dort ausführen. Hier füge ich die Statusleiste der Größe hinzu meiner Symbolleiste, die ich ein- und ausblende, zusammen mit der Statusleiste. Wenn es angezeigt wird, möchte ich, dass die Statusleiste darüber angezeigt wird, sodass ich die Höhe der Statusleiste zum oberen Abstand der Symbolleiste hinzufüge.

    binding.mainContent.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
        @Override
        public void onViewAttachedToWindow(View view) {
            binding.toolbar.setPadding(binding.toolbar.getPaddingLeft(),
                binding.toolbar.getPaddingTop() + getStatusBarHeight(),
                binding.toolbar.getPaddingRight(), binding.toolbar.getPaddingBottom());
            binding.mainContent.removeOnAttachStateChangeListener(this);
        }

        @Override
        public void onViewDetachedFromWindow(View view) {

        }
    });
Clyde
quelle
1

In Ordnung. Endgültige Antwort!!! Eine, die keine Nebenwirkungen hat, sich auf dokumentiertes Verhalten stützt, Q, Ausschnitte, Geräte mit unterschiedlicher Statusleistengröße je nach Ausrichtung usw. unterstützt.

protected void onCreate(Bundle savedInstanceState) {
     ...
     setContentView(R.layout.activity_main);
     ....
     // Use The topmost view of the activity, which 
    // is guaranteed to be asked about window insets/
     View rootView = findViewById(R.id.root_view_of_your_activity);
     ViewCompat.setOnApplyWindowInsetsListener(rootView, new OnApplyWindowInsetsListener() {
        @Override
        public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) 
    {
        //THIS is the value you want.
        statusBarHeight = insets.getSystemWindowInsetTop();

        // Let the view handle insets as it likes.
        return ViewCompat.onApplyWindowInsets(v,insets);
    }
});

Der Rückruf erfolgt nach onStart (), vor dem ersten Layout und gelegentlich danach.

Robin Davies
quelle
0

Dies mag nicht miteinander zusammenhängen, aber in den meisten Fällen besteht der Grund dafür, dass Benutzer nach der Höhe der Statusleiste suchen, darin, ihre eigenen Ansichten zu versetzen, damit sie nicht darunter platziert werden.

Wenn fitsSystemWindowsSie die Ansicht festlegen, die Sie "nach unten drücken" möchten, um der Statusleiste Platz zu geben, erfolgt dies automatisch und entsprechend der Größe der Statusleiste auf jedem Gerät. Der Ansicht, für die diese Eigenschaft festgelegt ist, wird eine Auffüllung hinzugefügttrue .

Beachten Sie, dass das Auffüllen nur der ersten Ansicht in der Hierarchie mit der fitSystemWindowsEinstellung auf hinzugefügt wirdtrue

Dies gilt beispielsweise für Fälle, in denen die Statusleiste durchscheinend ist. Stellen Sie sicher, dass Sie ein Thema für die Aktivität fitSystemWindowsfestlegen, die nicht festgelegt wurde. Andernfalls wird der Aktivität stattdessen der Abstand hinzugefügt (da er an erster Stelle in der Hierarchie steht).

Dieser Artikel ist eine gute Lektüre zu diesem Thema

lbarbosa
quelle
Beachten Sie, dass der konsistente Grund, warum Benutzer die Höhe der Statusleiste wünschen, darin besteht, dass "der ERSTEN Ansicht in der Hierarchie nur Auffüllungen hinzugefügt werden, was bei komplexen Layouts zu endlosen Problemen führt. Darüber hinaus verursachen CoordinatorLayouts und -Verhalten Chaos mit fitSystemWindows.
Robin Davies