到目前为止,我正在使用 Java 函数以编程方式设置背景颜色并获取 statusBar/navigationBar/cutout, 然而,如果它在当前的 Android API 35+ 中被弃用,它就会变得非常旧。
所以我尽可能多地谷歌搜索,使用许多示例来重新编写新函数,但是 statusBar、navigationBar 和 cutout 的高度总是返回零,这显然是错误的。
在下面的示例中,我用“OLD”注释了我如何使用工作代码,用“NEW”注释了不工作的新代码,用“NOTE”注释了我什至不知道的开放问题知道如何用 NEW 替换 OLD。
package org.myapp.activity;
import org.qtproject.qt.android.QtNative;
import org.qtproject.qt.android.bindings.QtActivity;
import android.os.*;
import android.content.*;
import android.app.*;
import android.content.res.Resources;
import android.content.res.Configuration;
import android.util.DisplayMetrics;
import android.view.Display;
import android.hardware.display.DisplayManager;
import android.view.Surface;
import android.view.View;
import android.view.DisplayCutout;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.graphics.Color;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsCompat.Type.InsetsType;
public class MyActivity extends QtActivity
{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setCustomStatusAndNavigationBar();
} // onCreate
void setCustomStatusAndNavigationBar() {
// First check sdk version, custom/transparent System_bars are only available after LOLLIPOP
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
// OLD: // The Window flag 'FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS' will allow us to paint the background of the status bar ourself and automatically expand the canvas
// OLD: // If you want to simply set a custom background color (including transparent) for the statusBar/navigationBar, use the following addFlags call
// OLD: window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// NOTE: I found no mention if this is even needed when not using setStatusBarcolor() anymore, but will use WindowInsets.Type.statusBars() - my guess its not needed anymore
// OLD: // The Window flag 'FLAG_TRANSLUCENT_NAVIGATION' will allow us to paint the background of the navigation bar ourself
// OLD: // But we will also have to deal with orientation and OEM specifications, as the navigationBar may or may not depend on the orientation of the device
// OLD: window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); // DEPRECATED (NOTE: is this even needed as setStatusBarColor() and setNavigationBarColor() are deprecated?)
// OLD: window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); // DEPRECATED
// NOTE: Use WindowInsetsController instead (NOTE: is this even needed as setStatusBarColor() and setNavigationBarColor() are deprecated?)
// OLD: Set StatusBar Transparent
// OLD: window.setStatusBarColor(Color.TRANSPARENT); // DEPRECATED
// NOTE: Draw proper background behind WindowInsets.Type#statusBars()} instead
// OLD: // Set NavigationBar to desired color (0xAARRGGBB) set alpha value to 0 if you want a solid color
// OLD: window.setNavigationBarColor(Color.TRANSPARENT); // DEPRECATED
// NOTE: Draw proper background behind WindowInsets.Type#navigationBars() instead
// OLD: // Statusbar background is now transparent, but the icons and text are probably white and not really readable, as we have a bright background color
// OLD: // We set/force a light theme for the status bar to make those dark
// OLD: View decor = window.getDecorView();
// OLD: decor.setSystemUiVisibility(decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); // DEPRECATED
// NOTE: Use WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS instead. I guess something like:
window.insetsController?.setSystemBarsAppearance(WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS); // for light mode, therefore dark foreground (text/icons)... NOTE: does it works on its own or do I need to set something specific, like addFlags() to make this work?
//window.insetsController?.setSystemBarsAppearance(0, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS); // for dark mode, therefore light foreground (text/icons)... NOTE: does it works on its own or do I need to set something specific, like addFlags() to make this work
// NOTE: Use WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS instead. I guess something like:
window.insetsController?.setSystemBarsAppearance(WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS); // for light mode, therefore dark foreground (text/icons)... NOTE: does it works on its own or do I need to set something specific, like addFlags() to make this work?
//window.insetsController?.setSystemBarsAppearance(0, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS); // for dark mode, therefore light foreground (text/icons)... NOTE: does it works on its own or do I need to set something specific, like addFlags() to make this work
}
}
// NOTE: used info from: outdated https://medium.com/javarevisited/how-to-get-status-bar-height-in-android-programmatically-c127ad4f8a5d / unfortunately not link to github so I cant use whole example inluding includes, which I assume is my main problem
public double statusBarHeight() {
// OLD: Using Resources (still working, but preferable use current API solution)
// double result = 0;
// int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
// if (resourceId > 0) {
// result = getResources().getDimension(resourceId);
// }
// return result;
// NEW: Using Window Insets (API 30+)
WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
double statusBarHeight = windowInsets.getInsets(WindowInsets.Type.statusBars()).top; // returns 0 all the time, why?
}
public int safeAreaTop() {
// OLD
// DisplayCutout cutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
// if(cutout != null) {
// int cutoutHeight = cutout.getSafeInsetTop();
// if (cutoutHeight > 0) {
// return cutoutHeight;
// }
// }
// return 0;
// NEW: Using Window Insets (API 30+)
WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
int cutoutHeight = windowInsets.getInsets(WindowInsets.Type.displayCutout()).top; // returns 0 all the time, but not sure if correctly as I use only Android Simualtor, but if statusBarHeight() solution is not working, I assume also this does not work
return cutoutHeight;
}
public double navigationBarHeight() {
// OLD: Using Resources (still working, but preferable use current API solution)
// double result = 0;
// int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
// if (resourceId > 0) {
// result = getResources().getDimension(resourceId);
// }
// return result;
// New: Using Window Insets (API 30+)
WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
double navigationBarHeight = windowInsets.getInsets(WindowInsets.Type.navigationBars()).bottom; // returns 0 all the time, but not sure if correctly as I use only Android Simualtor without navigationBar, but if statusBarHeight() solution is not working, I assume also this does not work
return navigationBarHeight;
}
public int getNavigationBarPosition() {
Resources res = getResources();
int resourceId = res.getIdentifier("config_showNavigationBar", "bool", "android");
boolean hasMenu = false;
if (resourceId > 0) {
hasMenu = res.getBoolean(resourceId);
}
if (!hasMenu) {
return -1;
}
// NOTE: https://stackoverflow.com/questions/69724946/getdisplay-return-display
// Display display = getWindowManager().getDefaultDisplay(); // OLD: getDefaultDisplay() DEPRECATED
DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); // NEW solution, currently untested
Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
int rotation = display.getRotation();
switch (rotation) {
case Surface.ROTATION_90:
return 1;
case Surface.ROTATION_180:
return 3;
case Surface.ROTATION_270:
return 2;
default:
return 0;
}
}
}
我可以请求检查和解释我在这里做错了什么,并更正正确的工作代码应该是什么样子吗?
PS:我不是 Java 专家,我在 QT(所以 C++/QML)中工作,这是我的应用程序从 Java 界面进行管理所需的唯一东西
新的 Android 15 行为阐明了您需要执行的操作类型。 https://developer.android.com/about/versions/15/behavior-changes-15#ux
不确定在哪里调用和使用诸如 safeAreaTop 之类的东西,但您应该在它们应用于特定视图(本例中为 binding.homeFrame )时获取 Insets,并根据需要更新该视图的填充或边距
ViewCompat.setOnApplyWindowInsetsListener(binding.homeFrame) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
v.updatePadding(insets.left, 0, insets.right, insets.bottom)
WindowInsetsCompat.CONSUMED
}