状态栏的高度?

有没有办法得到状态栏 + 标题栏的高度?检查开发人员论坛显示相同的问题,但没有解决方案(我可以找到)。

我知道我们可以在初始布局通过之后得到它,但是我希望在我的活动的 onCreate ()中得到它。

谢谢

96349 次浏览
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()方法的状态栏的高度,使用这个方法:

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

在 onCreate 方法中将一个可运行的视图附加到其中一个视图,并将上面的代码放入其中。这将导致应用程序计算状态栏 + 标题屏幕高度时,他们附加到屏幕上。

看看下面的代码:

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;


}


});

如果这仍然不起作用,尝试调用视图的 postDelayed 方法而不是 post,并添加一个毫秒值作为第二个参数。

我认为更好的计算方法是得到全屏幕的高度减去我们的主要布局

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

你可以把它放在 onGlobalLayout()里。这在平板电脑上也可以用,我在 Theme.NoTitleBar 上试过,但它必须总是可以用。

也许你甚至可以增强它,并使用它的 onCreate()改变 mainView.getHeight()mainView.getMeasuredHeight()

我建议下一个代码:

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

两个例子:

1)器件1 品牌: 三星, 设备: Maguro, 金枪鱼, Cpu _ abi: armeabi-v7a, 显示器: ICL53F.M420KREL08, 制造商: 三星, 型号: Galaxy Nexus, 版本: 4.0, 十四岁;

屏幕分辨率: 1280 x 720。这个设备上没有硬件按钮。

结果:

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;

设备1在屏幕顶部有标题栏,在屏幕底部有软件按钮。

2)设备2 装置: Bravo, 太棒了, Cpu _ abi: armeabi-v7a, 显示器: FRG83G, 制造商: 宏达电, 型号: HTC Desire, 版本: 2.2.2, Sdk: 8,

屏幕分辨率: 800 x 400。这个设备有硬件按钮。

结果:

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;

设备2在屏幕顶部有标题栏,而没有状态栏。

以上提出了两种解决办法:

A) v.getTop() - rect.top

(设备1不正确-它给出0而不是72)

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

(设备2不正确-它给出0而不是38)

变体:

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

在这两种情况下都给出了正确的结果。

更新

3)再举一个例子(第三个器件) : 品牌: LGE, 设备: v909, Cpu _ abi: armeabi-v7a, 显示器: HMJ37, 型号: LG-V909, 版本: 3.1, 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

设备3具有水平方向,在屏幕顶部没有标题栏,在屏幕底部有状态栏。

所以,这里:

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

对于2号和3号设备来说是正确的。我不太确定设备1。用户发给我设备1的截图。这里有一个带有软件按钮的状态栏。但是表达式“ display.getHeight ()-v.getBottom ()”给出0。

您还可以使用 这篇博文描述的方式获取在 android 的 diments.xml 文件中找到的状态栏的维度。

这可以获得状态栏的高度,而不需要等待绘图。

引用博文中的代码:

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

您需要将此方法放在 ContextWrapper 类中。

虽然这是一个老问题,但我发现答案在 onCreate()中不起作用:

我从 给你中找到了这段代码,它在 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;
}

我希望这对遇到这个问题的人有所帮助。

Jorgesys 发布的解决方案非常好,但是在 onCreate ()方法内部不起作用。 我猜这是因为状态栏和标题栏是在 onCreate ()之后创建的。

解决方案很简单——您应该将代码放在 runnable 中,然后使用 root.post((Runnable action) );在 onCreate ()之后执行它

所以整个解决方案是:

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

我发现它 给你

对于那些想在 XML 布局中使用它的人,比如我:

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

不要被 Android Studio (2.2 Preview 3——在编写本文的时候)不支持这个概念所迷惑。运行库可以。我从谷歌的源代码里找到的。

对于 API 23,有一个获得状态栏高度的更好的解决方案。API 23增加了一个 WindowInsets特性,因此您可以使用这段代码来获取系统插入的大小,在本例中是在顶部。

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

请注意,getRootWindowInsets()将返回 null,直到视图被附加到一个窗口,所以它不能直接在 onCreate()中使用,但是你可以为窗口附加添加一个监听器,并在那里执行-在这里,我将添加状态栏插入到我的工具栏的大小,我隐藏和显示,连同状态栏。当它显示时,我希望状态栏在它的顶部,所以我将状态栏高度添加到工具栏的顶部填充。

    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) {


}
});

获得状态栏高度的支持方法是从 API 21 + 开始使用 WindowInsets类:

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

WindowInsetsCompat支援图书馆:

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

您还可以在视图中重写 onApplyWindowInsets方法:

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

关于进一步的细节,我建议检查 Chris Banes talk-成为窗户装配大师(可用的 给你幻灯片)。

这可能看起来没有关系,但是大多数时候,人们查找状态栏高度的原因是为了抵消他们自己的视图,这样他们就不会被置于状态栏下面。

通过在视图上设置 fitsSystemWindows,您想要“按下”以给状态栏留出空间,它将自动完成,并根据每个设备上的状态栏的大小。将向将此属性设置为 true的视图添加填充。

请记住,只有当 fitSystemWindows设置为 true时,填充才会添加到层次结构中的第一个视图

这适用于状态栏是半透明的情况,例如。确保为没有设置 fitSystemWindows的活动设置主题,否则将向活动添加填充(因为它是层次结构中的第一个)。

这篇文章 是关于这个主题的一个很好的阅读材料

好吧。最终答案! ! !一个没有副作用,依赖于文件的行为,支持 Q,剪切,设备的不同状态栏大小取决于方向,等等。

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

回调发生在 onStart ()之后、第一次布局之前,偶尔在此之后。

针对 API 30,我已经成功地使用了更新的 Nicklas 答案(参考文献: https://stackoverflow.com/a/47125610/2163045)

在我的示例中,我在全屏 WindowCompat.setDecorFitsSystemWindows(window, false)活动中动态调整自定义工具栏高度

在 GooglePixel5上测试

class MyActivity : ViewBindingActivity<LayoutBinding>() {
...


override fun created(binding: LayoutBinding, savedInstanceState: Bundle?) {


binding.root.setOnApplyWindowInsetsListener { _, insets ->
val statusBarHeight = insets.getInsets(WindowInsets.Type.statusBars()).top // <- HERE YOU ARE
val toolbarHeight = getDimenPx(R.dimen.toolbar_height)
binding.toolbar.layoutParams.height = statusBarHeight + toolbarHeight
insets
}
}
}

目前的实际方式:

ViewCompat.setOnApplyWindowInsetsListener(toolbar) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars())
view.updateLayoutParams<MarginLayoutParams> {
topMargin = insets.top
}
WindowInsetsCompat.CONSUMED
}

如果你想使用 在你的应用程序中支持边到边,谷歌建议你这样使用它。