Painting behind system bars using Qt/Qml
-
Hello and thanks for the great work...
in nowadays.. wouldnt be posisble you would rewrite to Qt6?EDIT: basicaly I only replaced:
const QAndroidJniObject activity = QtAndroid::androidActivity();
by
QJniObject activity = QNativeInterface::QAndroidApplication::context();
and of course include proper header:
// for whatever reason i cant pass this include here as Qt spam bot wont allow
and seems to work fine...
however, as I looked through the code, the height of status/navi bar it returns only in Android, correct?
there is no *.mm to figure out the height of bars in iOSUnfortunatelly, i can not test... however ive spend also huge amount of time to figure this time, most helpful (but also outdated) info i gathered from:
which also includes the function to get height of statusbar in iOS via *.mm file...
https://sudonull.com/post/73911-Native-Android-and-iOS-code-in-Qt-using-status-bar-as-an-example
so how can we combine this also with your best solution?EDIT2: and huge cherry on the top would be to be able to change status/navi bar foreground style between dark and light :D so if our content will be light, then we can set the time and other stuff in statusbar to dark text color so its readable
-
const QAndroidJniObject activity = QtAndroid::androidActivity();
does not work on Qt6, so I replaced by:
QJniObject activity = QNativeInterface::QAndroidApplication::context();
maybe i did few other little modifications on the way to make it work on Qt6, I will check bit later.
Anyway... as I cant test it now without Mac, does this also work for iOS?
As I dont see included mm file to gather info like://[UIApplication sharedApplication].statusBarFrame.size.height; // deprecated by iOS11 [UIApplication sharedApplication].windows.firstObject.safeAreaInsets.top; // probably current iOS support? //[UIApplication sharedApplication].keyWindow.safeAreaInsets.top; // one of options to gather, need to test //[UIApplication sharedApplication].windows[0].safeAreaInsets.top; // one of options to gather, need to test //[UIApplication sharedApplication].delegate.windows.safeAreaInsets.top; // one of options to gather, need to test
I cant imagine how QT can know this safeArea margins on its own
-
Hi @shokarta
just now noticed your edits in the earlier posts ! I didn't get a notification for that, so sorry about that!
Anyway... as I cant test it now without Mac, does this also work for iOS?
As I dont see included mm file to gather info like:for iOS there are no extra steps needed. in safe area.h you'll see
#if !defined (Q_OS_ANDROID) QPlatformWindow *platformWindow = static_cast<QPlatformWindow *>(window->handle()); if(!platformWindow) return QVariantMap(); margins = platformWindow->safeAreaMargins(); #else
QPlatformWindow worked perfectly fine for iOS. Well not entirely correct, the changed signal is emitted before new safe areas are actually able to be read, IIRC. That's why the timer is in the QML file.
does not work on Qt6, so I replaced by:
....ok makes sense, I'll have to compile and update it for Qt6 than. Can't leave it incomplete! I'll end up switching to Qt6 myself someday too
-
-
@J-Hilk I have spent couple days to update it to current SDK as half of stuff are deprecated.
Its 100% based on your example :D
would there be possible you could have a quick look to see why it returns 0 when obviously it shall return a values?
I think there would be only some import missing... however as I never worked with java, I can not know :(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); setCustomStatusAndNavBar(); } // onCreate void setCustomStatusAndNavBar() { // 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(); // 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 // If you want to simply set a custom background color (including transparent) for the statusBar/navigationBar, use the following addFlags call window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); // The Window flag 'FLAG_TRANSLUCENT_NAVIGATION' will allow us to paint the background of the navigation bar ourself // 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 //window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); // DEPRECATED (NOTE: is this needed as also setStatusBarColor() and setNavigationBarColor() are deprecated?) window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); // DEPRECATED // TODO: Use WindowInsetsController instead (NOTE: is this needed as also setStatusBarColor() and setNavigationBarColor() are deprecated?) // Set StatusBar Transparent window.setStatusBarColor(Color.TRANSPARENT); // DEPRECATED // TODO: Draw proper background behind WindowInsets.Type#statusBars()} instead //Set NavigationBar to desired color (0xAARRGGBB) set alpha value to 0 if you want a solid color window.setNavigationBarColor(Color.TRANSPARENT); // DEPRECATED // TODO: Draw proper background behind WindowInsets.Type#navigationBars() instead // Statusbar background is now transparent, but the icons and text are probably white and not really readable, as we have a bright background color // We set/force a light theme for the status bar to make those dark View decor = window.getDecorView(); decor.setSystemUiVisibility(decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); // DEPRECATED (NOTE: is this needed as also setStatusBarColor() and setNavigationBarColor() are deprecated?) } } // outdated https://medium.com/javarevisited/how-to-get-status-bar-height-in-android-programmatically-c127ad4f8a5d public double statusBarHeight() { // Method 1: 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; // Method 2: Using Window Insets (API 30+) WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets(); double statusBarHeight = windowInsets.getInsets(WindowInsets.Type.statusBars()).top; // returns 0 (wrongly) return statusBarHeight; // Method 3: Using Display Metrics // Rect rectangle = new Rect(); // Window window = getWindow(); // window.getDecorView().getWindowVisibleDisplayFrame(rectangle); // int statusBarHeight = rectangle.top; // return statusBarHeight; } public int safeAreaTop() { // Still working, but preferable use current API solution // DisplayCutout cutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout(); // if(cutout != null) { // int cutoutHeight = cutout.getSafeInsetTop(); // if (cutoutHeight > 0) { // return cutoutHeight; // } // } // return 0; // Using Window Insets (API 30+) WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets(); int cutoutHeight = windowInsets.getInsets(WindowInsets.Type.displayCutout()).top; // returns 0 (wrongly) return cutoutHeight; } // If we decide to draw the behind the navigationBar, we need to know the new safearea, // so to not draw text or position buttons behind the nav bar. // Those would be unclickable and potentially unreadable. // ATTENTION: // Compared to the statuBbar, there is no guarantee that the behind will be at the bottom of your screen // This function returns the hight of the Navigation bar */ public double navBarHeight() { // Method 1: 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; // Method 2: Using Window Insets (API 30+) WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets(); double navigationBarHeight = windowInsets.getInsets(WindowInsets.Type.navigationBars()).top; // returns 0 (wrongly) return navigationBarHeight; // Method 3: Using Display Metrics // Rect rectangle = new Rect(); // Window window = getWindow(); // window.getDecorView().getWindowVisibleDisplayFrame(rectangle); // int navigationBarHeight = rectangle.bottom; // return navigationBarHeight; } public int getNavBarPosition() { 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; } // https://stackoverflow.com/questions/69724946/getdisplay-return-display // Display display = getWindowManager().getDefaultDisplay(); // getDefaultDisplay() deprecated DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE); 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; } } }
-
This post is deleted!
-
I am Qt6.5.3, as shown in the picture. How can I modify the system status bar to be fully transparent? I want the status bar of Android to have the same color as the interface of the application, but I have been unable to achieve this
-
Hi and welcome,
it would have better to start a new topic for your issue.
Anyway, now that you created it here, check out this github repo, it might help: