Android中状态栏的高度


332

Android中状态栏的高度是多少?总是一样吗?

从我的测量来看,它似乎是25dp,但是我不确定在所有平台上它是否具有相同的高度。

(我想知道这可以正确地实现从没有状态栏的活动到具有状态栏的活动的渐变过渡)


如果进行交叉淡入淡出,则无需知道状态栏的高度。
secretthcopter

2
我确实需要它,因为有些元素在布局中居中,我希望它们彼此淡入。
hpique 2010年

Answers:


363

在... 状态栏的高度之前已回答了这个问题

更新 ::

当前方法:

好的,状态栏的高度取决于屏幕尺寸,例如,在屏幕尺寸为240 X 320的设备中,状态栏高度为20px,对于屏幕尺寸为320 X 480的设备,状态栏高度为25px,对于480 x 800的设备,状态栏高度必须为38px

所以我建议使用此脚本来获取状态栏的高度

Rect rectangle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
int statusBarHeight = rectangle.top;
int contentViewTop = 
    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight= contentViewTop - statusBarHeight;

   Log.i("*** Elenasys :: ", "StatusBar Height= " + statusBarHeight + " , TitleBar Height = " + titleBarHeight); 

(旧方法)要获取“ onCreate()活动” 方法上状态栏的高度,请使用以下方法:

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

不完全是。我还问我是否可以假设状态栏在所有设备中都具有相同的高度。
hpique 2010年

16
还是用蘸酱?如果始终为25dip,则不需要代码。
hpique 2010年

8
您不能假设它始终为25dp(例如,检查点燃火的高度)。
DallinDyer 2012年

1
在onCreate()中传递给view.post()的runnable中不起作用-返回0
Ixx

4
window.getDecorView().getWindowVisibleDisplayFrame(rectangle)如果您处于多窗口模式+纵向旋转+第二窗口,则不是获取状态栏高度的正确方法。您将获得巨大的价值(包括第一高度)。
团洲镇

211

在我用来获取状态栏高度的所有代码示例中,实际上唯一可以使用的onCreate方法工作的示例Activity是:

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

显然,状态栏的实际高度将保留为Android资源。可以将以上代码添加到ContextWrapper类(例如Activity)中。

http://mrtn.me/blog/2012/03/17/get-the-height-of-the-status-bar-in-android/中找到


与其进行硬编码,不如进行动态计算。上面的方法对我有用!
炼金术士

您不应该使用getDimension(...)代替吗?
Android开发人员

6
请注意-并非在所有设备上都适用。例如,在Transformer TF201(以及TF101,TF300和某些其他设备)上,高度报告为25,其中没有状态栏。
BłażejCzapp

4
基于上面的评论,在我看来,代码告诉您特定设备上状态栏的高度,而不是特定活动(实际上可能没有状态栏)上的高度。
晕眩

在XML中,可以使用dimen资源“ @android:dimen / status_bar_height”。<!-在Android系统源文件中定义的状态栏的高度-> <dimen name =“ status_bar_height”> 24dp </ dimen>。但是您不能在应用程序项目中直接引用它。因此,您必须使用代码。
Tshunglee

48

在MDPI设备上,状态栏为25px。我们可以将其用作基础并乘以密度(向上舍入)以获取任何设备上状态栏的高度:

int statusBarHeight = Math.ceil(25 * context.getResources().getDisplayMetrics().density);

供参考:ldpi = .75,mdpi = 1,hdpi = 1.5,xhdpi = 2


6
这对于具有状态栏的设备是正确的。请注意,由于以上内容已被编写,因此并非所有设备都拥有一个设备。具体来说,运行ICS的设备可能在底部具有组合的状态/导航栏,而在顶部则完全没有。因此,在这种情况下,出于大多数编程目的,您希望将状态栏的高度设置为零,但是上面的公式将为您提供非零的大小。
卡尔

1
同样25px的值对于所有mdpi设备也不正确。它可以根据API级别而有所不同。例如,10.1 WXGA平板电脑仿真器设备在API 16和19上报告25px,但在API 24上报告
24px。– jk7

48

硬编码大小或使用反射来获取的值status_bar_height被认为是不好的做法。克里斯· 贝恩斯( Chris Banes)在纽约Droidcon大会上谈到了这一点。推荐的获取状态栏大小的方法是通过OnApplyWindowInsetsListener

myView.setOnApplyWindowInsetsListener { view, insets -> {
  val statusBarSize = insets.systemWindowInsetTop
  return insets
}

这是在API 20中添加的,也可以通过ViewAppCompat向后移植。


这是今天最准确的答案
基思(keith)'18

对我来说,这只会触发一次,如果我通过底部导航有碎片。如果我再次替换该片段,则不会调用此侦听器,是否还有兼容的吸气剂?
urSus

74
但是这个API太可怕了,因为幕后的WTF / Gotchas数量巨大。您以为可以使用任何视图进行操作,但是不可以,您需要重写某些内容并确保将插图传递给孩子(??),因为某些ViewGroups(材料设计)会(其他)(线性布局?ConstraintLayout?你好?)。而不是拥有Window.getStatusBarSize()的系统……我们必须订阅一个令人讨厌的听众……回家Android,您醉了。只是硬编码大小,直到Google醒来,我们就在2018年。我希望Chris Banes看到这一天……
Martin Marconcini

就我而言,它没有被解雇。我把它称为Activity#onCreated。我做错什么了吗?另外,为什么不使用mView.getRootWindowInsets()?
阿迪尔·阿利耶夫

34

我将一些解决方案合并在一起:

public static int getStatusBarHeight(final Context context) {
    final Resources resources = context.getResources();
    final int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0)
        return resources.getDimensionPixelSize(resourceId);
    else
        return (int) Math.ceil((VERSION.SDK_INT >= VERSION_CODES.M ? 24 : 25) * resources.getDisplayMetrics().density);
    }

另一种选择:

    final View view = findViewById(android.R.id.content);
    runJustBeforeBeingDrawn(view, new Runnable() {
        @Override
        public void run() {
            int statusBarHeight = getResources().getDisplayMetrics().heightPixels - view.getMeasuredHeight();
        }
    });

编辑:替代runJustBeforeBeingDrawn:https ://stackoverflow.com/a/28136027/878126


getResources()。getDisplayMetrics()。heightPixels -getActivity()。findViewById(android.R.id.content).getMeasuredHeight()在android lolipop中不起作用
abbasalim

@ ArMo372更新了答案。只是视图需要首先通过度量。如果您已经传递过runJustBeforeBeingDrawn,则无需使用它。您只会在过早的情况下使用它。
Android开发人员

28

根据Google设计指南;状态栏的高度为24 dp。

如果要获取状态栏的高度(以像素为单位),可以使用以下方法:

private static int statusBarHeight(android.content.res.Resources res) {
    return (int) (24 * res.getDisplayMetrics().density);
}

可以通过以下方式从活动中调用:

statusBarHeight(getResources());

18
直到棉花糖是25dp。自棉花糖以来24dp。
Eugen Pechanec 2015年

1
这实质上是对值进行硬编码-不允许进行设计更改
Siliconeagle

1
并且不考虑在相同情况下不会显示状态栏的事实
jk7

19

默认高度为25dp。使用Android Marshmallow(API 23)时,高度降低到24dp。

更新:请注意,自从开槽和使用冲孔相机的时代开始以来,对状态栏使用静态高度就不再起作用。请改用窗口插图!


1
甜!我刚刚专门为API级别23+创建了dimens.xml,其中将高度硬编码为24dp。
某处某人

18

这也适用于Refreence 链接

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

13

我有一个同样的问题,必须在onCreate中获取状态栏的高度。这对我有用。

private static final int LOW_DPI_STATUS_BAR_HEIGHT = 19;

private static final int MEDIUM_DPI_STATUS_BAR_HEIGHT = 25;

private static final int HIGH_DPI_STATUS_BAR_HEIGHT = 38;

在onCreate内:

DisplayMetrics displayMetrics = new DisplayMetrics();
((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);

int statusBarHeight;

switch (displayMetrics.densityDpi) {
    case DisplayMetrics.DENSITY_HIGH:
        statusBarHeight = HIGH_DPI_STATUS_BAR_HEIGHT;
        break;
    case DisplayMetrics.DENSITY_MEDIUM:
        statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
        break;
    case DisplayMetrics.DENSITY_LOW:
        statusBarHeight = LOW_DPI_STATUS_BAR_HEIGHT;
        break;
    default:
        statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
}

看到:

http://developer.android.com/reference/android/util/DisplayMetrics.html http://developer.android.com/guide/practices/ui_guidelines/icon_design.html


3
我喜欢您使用密度驱动值的想法。如果要在多个位置使用代码(或使用其他与密度相关的值),则我更喜欢将工作卸载到系统中,并将这些值存储在dimen资源中,这使切换变得不必要。您确实需要为每个密度创建一个特定于维度的文件夹和资源文件。最终资源res = context.getResources(); int statusbarHeight = 0; 尝试{statusbarHeight = res.getDimensionPixelSize(R.dimen.android_statusbar_height); } catch(NotFoundException e){}
ProjectJourneyman 2011年

5
对这些值进行硬编码很危险,如果它们在更高的平台版本中更改,该怎么办?
David Snabel-Caunt

我认为与其使用硬编码的像素大小(每个密度一个),不如使用“ 25dp”。
Android开发人员


12

是的,当我尝试使用View时,它提供25px的结果。这是整个代码:

public class SpinActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout lySpin = new LinearLayout(this);
        lySpin.setOrientation(LinearLayout.VERTICAL);       
        lySpin.post(new Runnable()
        {
            public void run()
            {
                Rect rect = new Rect();
                Window window = getWindow();
                window.getDecorView().getWindowVisibleDisplayFrame(rect);
                int statusBarHeight = rect.top;
                int contentViewTop = 
                    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
                int titleBarHeight = contentViewTop - statusBarHeight;
                System.out.println("TitleBarHeight: " + titleBarHeight 
                    + ", StatusBarHeight: " + statusBarHeight);
            }
        }
    }
}

当我像上面所做的那样创建新的线性布局时,但是当我从xml找到lySpin的findviewbyid时,以上代码为我工作。然后返回null。不了解你的行为。
Shaista Naaz

因为布局尚未在onCreate中知道其大小,因为尚未完成绘制。我通常要做的是在onCreate上的UI线程上发布一个Runnable,它使UI有时间进行绘制。
杰森·罗宾逊

8

240x320-20px

320x480-25像素

480x800 +-38px


3
这不再准确。使用一种测量状态栏的方法。
迈克尔

7

尝试这个:

    Rect rect = new Rect();
    Window win = this.getWindow();
    win.getDecorView().getWindowVisibleDisplayFrame(rect);
    int statusBarHeight = rect.top;
    int contentViewTop = win.findViewById(Window.ID_ANDROID_CONTENT).getTop();
    int titleBarHeight = contentViewTop - statusBarHeight;
    Log.d("ID-ANDROID-CONTENT", "titleBarHeight = " + titleBarHeight );

在活动的onCreate方法中它对我不起作用,但是当我将其放入onClickListener并给我25的测量值时


我怀疑在他在onCreate()上进行测试时,状态栏尚未创建。相反,当他手动单击以激活他的onClickListener()代码时,该条已经有足够的思考时间来显示,并且他能够检索其大小。
卡尔

6

在Android 6.0中,状态栏的高度为24dp

 <!-- Height of the status bar -->
 <dimen name="status_bar_height">24dp</dimen>
 <!-- Height of the bottom navigation / system bar. -->
 <dimen name="navigation_bar_height">48dp</dimen>

您可以在源代码中找到答案:frameworks \ base \ core \ res \ res \ res \ values \ dimens.xml


有没有办法在我们的XML中获取此资源?@android:dimen/status_bar_height不适用于我
Patrick

4

为了解决这个问题,我使用了一种组合方法。这是必要的,因为在平板电脑上,调用display.getHeight()时,系统栏已经减去了它的像素。因此,我首先检查是否存在系统栏,然后检查Ben Claytons的方法,该方法在手机上可以正常工作。

public int getStatusBarHeight() {
    int statusBarHeight = 0;

    if (!hasOnScreenSystemBar()) {
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = getResources().getDimensionPixelSize(resourceId);
        }
    }

    return statusBarHeight;
}

private boolean hasOnScreenSystemBar() {
    Display display = getWindowManager().getDefaultDisplay();
    int rawDisplayHeight = 0;
    try {
        Method getRawHeight = Display.class.getMethod("getRawHeight");
        rawDisplayHeight = (Integer) getRawHeight.invoke(display);
    } catch (Exception ex) {
    }

    int UIRequestedHeight = display.getHeight();

    return rawDisplayHeight - UIRequestedHeight > 0;
}

3

感谢@Niklas +1,这是正确的方法。

public class MyActivity extends Activity implements android.support.v4.View.OnApplyWindowInsetsListener {

    Rect windowInsets;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.my_activity);

        View rootview = findViewById(android.R.id.content);

        android.support.v4.View.ViewCompat.setOnApplyWindowInsetsListener(rootview, this);
    }

    android.support.v4.View.WindowInsetsCompat android.support.v4.View.OnApplyWindowInsetsListener.OnApplyWindowInsets(View v, android.support.v4.View.WindowInsetsCompat insets)
    {
        windowInsets = new Rect();
        windowInsets.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
        //StatusBarHeight = insets.getSystemWindowInsetTop();

        //Refresh/Adjust view accordingly

        return insets;
    }
}

如果代码不是100%正确,请原谅,将其从Xamarin C#转换而来,但这只是它的原因。适用于缺口等


2

切换全屏解决方案:

此解决方案可能看起来像一种解决方法,但实际上它说明了您的应用是否为全屏显示(也就是隐藏状态栏):

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point(); display.getSize(size);
int barheight = size.y - findViewById(R.id.rootView).getHeight();

这样,如果您的应用当前处于全屏模式,barheight则等于0。

我个人必须使用它来更正绝对的TouchEvent坐标,以解决状态栏的问题:

@Override
public boolean onTouch(View view,MotionEvent event) {
    Display display = getWindowManager().getDefaultDisplay();
    Point size = new Point(); display.getSize(size);
    int YCoord = (int)event.getRawY() - size.y + rootView.getHeight());
}

无论应用程序是否为全屏显示,都将获得绝对的y坐标。

请享用


谢谢,这也是在显示Android键盘时唯一适用于我的解决方案。
Thiago Moura

2

在Android 4.1及更高版本上,您可以将应用程序的内容设置为显示在状态栏的后面,以使内容不会随着状态栏的隐藏和显示而调整大小。为此,请使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN。您可能还需要使用SYSTEM_UI_FLAG_LAYOUT_STABLE来帮助您的应用维持稳定的布局。

使用这种方法时,您有责任确保应用程序UI的关键部分(例如,Maps应用程序中的内置控件)最终不会被系统栏覆盖。这可能会使您的应用无法使用。在大多数情况下,您可以通过将android:fitsSystemWindows属性添加到XML布局文件(设置为true)来处理此问题。这将调整父ViewGroup的填充以为系统窗口留出空间。这对于大多数应用程序来说已经足够了。

但是,在某些情况下,您可能需要修改默认填充以获取所需的应用布局。要直接操纵内容相对于系统栏的布局方式(系统栏占据着一个窗口的“内容插入物”空间),请覆盖fitSystemWindows(Rect插入物)。当窗口的内容插入更改时,视图层次结构将调用fitSystemWindows()方法,以允许窗口相应地调整其内容。通过覆盖此方法,您可以根据需要处理插图(以及应用程序的布局)。

形式:https//developer.android.com/training/system-ui/status.html#behind


1

如果您确切知道尺寸VS高度

喜欢

例如,在屏幕尺寸为320 X 480的设备中,状态栏高度为25px,对于屏幕尺寸为480 x 800的设备,状态栏高度必须为38px

那么您就可以获取视图的宽度/屏幕大小,只需使用if else语句即可获取状态栏的高度


以我的经验,高度似乎是基于密度而不是屏幕尺寸。当然,密度本身通常与屏幕尺寸有关,因此存在间接关系。例如,我以前的Moto Droid具有480x854(而不是480x800)的显示屏,并且状态栏也高38像素。
卡尔2012年

他们为此发明了dp(密度独立像素)
Roel 2014年

1

最佳答案对某些人不起作用的原因是,在准备好渲染视图之前,您无法获得视图的尺寸。OnGlobalLayoutListener实际上可以使用来获得上述尺寸:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final ViewGroup decorView = (ViewGroup) this.getWindow().getDecorView();
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= 16) {
                decorView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            } else {
                // Nice one, Google
                decorView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
            Rect rect = new Rect();
            decorView.getWindowVisibleDisplayFrame(rect);
            rect.top; // This is the height of the status bar
        }
    }
}

这是最可靠的方法。


1
@androiddeveloper OnGlobal!= GlobalOn
marijnz0r

@ marijnz0r多么奇怪。怎么办
Android开发人员

@androiddeveloper我不知道,但是我碰巧也和几天前一样。请参阅:stackoverflow.com/a/19216041/4587214
marijnz0r

@ marijnz0r所以两者都一样。让我想起了其他情况,他们为已经存在的东西重新命名,并弃用了以前的东西。例如“FILL_PARENT”与“match_parent”:developer.android.com/reference/android/view/...
Android开发者

1

由于现在可以使用多窗口模式,因此您的应用程序顶部可能没有状态栏。

以下解决方案将自动为您处理所有情况。

android:fitsSystemWindows="true"

或以编程方式

findViewById(R.id.your_root_view).setFitsSystemWindows(true);

您还可以通过以下方式获得根视图

findViewById(android.R.id.content).getRootView();
or
getWindow().getDecorView().findViewById(android.R.id.content)

有关获取root-view的更多详细信息,请参阅-https: //stackoverflow.com/a/4488149/9640177


0

由于Pixel 3XL的缺口,这个问题最近对我来说很重要。我真的很喜欢android开发人员的解决方案,但我希望能够随意获取状态栏的高度,因为这对于我需要播放的全屏动画特别有必要。以下功能启用了可靠的查询:

private val DEFAULT_INSET = 96
fun getInsets(view: View?): Int {
     var inset = DEFAULT_INSET
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//Safe because only P supports notches
          inset = view?.rootWindowInsets?.stableInsetTop ?: DEFAULT_INSET
     }
     return inset
}

fun blurView(rootView: View?, a: SpacesActivity?) {
    val screenBitmap = getBitmapFromView(rootView!!)
    val heightDifference = getInsets(rootView)
    val croppedMap = Bitmap.createBitmap(
                    screenBitmap, 0, heightDifference,
                    screenBitmap.width,
                    screenBitmap.height - heightDifference)
    val blurredScreen = blurBitmap(croppedMap)
    if (blurredScreen != null) {
         val myDrawable = BitmapDrawable(a!!.resources, blurredScreen)
         a.errorHudFrameLayout?.background = myDrawable
         a.appBarLayout?.visibility = View.INVISIBLE
   }
}

然后在活动类中:

fun blurView() {
    this.runOnUiThread {
        Helper.blurView(this)
    }
}

当然,您会希望将活动的弱引用传递给静态Helper类方法参数,但是为了简洁起见,在本示例中,我将其省略。在blurBitmaperrorHudFrameLayout被省略,同样的原因,因为它们不直接涉及到获得状态栏的高度。


如果适用于Android P及更高版本,为什么还要使用Android M?另外,如果没有View实例,该怎么办?例如,如果您当前没有活动...
android开发人员

M是最早可以检查stableInsetTop的方法,即使只支持P支持的槽口,我还是希望获得实际的插入量,而不是回到我可以的默认位置。如果您没有任何活动,则此解决方案不起作用。
詹姆斯·乔丹·泰勒

我知道了。谢谢。您能否显示一个更“完整”的示例?
Android开发人员

我将上面的答案更改为在示例中使用该方法。
詹姆斯·乔丹·泰勒

我的意思是一个可行的例子,但是还可以。
android开发人员

0

结合两个最佳解决方案的Kotlin版本

fun getStatusBarHeight(): Int {
    val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
    return if (resourceId > 0) resources.getDimensionPixelSize(resourceId)
    else Rect().apply { window.decorView.getWindowVisibleDisplayFrame(this) }.top
}
  1. 注意到status_bar_height值(如果存在)
  2. 如果status_bar_height不存在,则根据“窗口装饰”计算状态栏的高度
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.