Android API 35+ 来自 Java 的状态/导航栏颜色/高度

问题描述 投票:0回答:1

到目前为止,我正在使用 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 界面进行管理所需的唯一东西

java android qt qt6 windowinsets
1个回答
0
投票

新的 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
    }
© www.soinside.com 2019 - 2024. All rights reserved.