Has anyone worked around iOS safe zone margins, like with iPhone X?
-
UIKit in iOS 11 has new features for laying out your main view without overlapping built-in device controls and bezels, for example on the iPhone X. Has anyone played out their widgets according to these? I have some strange behavior with my QGraphicsView and QWidget overlays, which should be full screen (see screenshot):
I suppose I would like to know what the margins are and also how to prevent my view from automatically being restricted to the safe zone. Some elements need to be drawn differently, and some simply need to go outside the safe zones to the actual edges of the screen.
Here are two links describing how to handle this in swift:
-
Hi @patrickkidd
These links might help you.
Sample code for QML.
ApplicationWindow { id: root flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | (Qt.platform.os === "ios" ? Qt.MaximizeUsingFullscreenGeometryHint : 0) }
// This function is to support the iPhone X Series notch issue - status bar size is 44pt function toolbarMarginSupport() { if (isIPad || (Qt.platform.os === "ios" && isPortraitMode)) { switch(windowScreen.height * windowScreen.devicePixelRatio) { case 1624: // iPhone_XR (Qt Provided Physical Resolution); case 1792: // iPhone_XR; case 2436: // iPhone_X_XS; case 2688: // iPhone_XS_MAX; return 44; default: return 20; } } else { return 0; } } function isIPhoneXSeries() { if (isIPad || (Qt.platform.os === "ios" && isPortraitMode)) { switch(windowScreen.height * windowScreen.devicePixelRatio) { case 1624: // iPhone_XR (Qt Provided Physical Resolution); case 1792: // iPhone_XR; case 2436: // iPhone_X_XS; case 2688: // iPhone_XS_MAX; return true; default: return false; } } else { return false; } }
All the best.
-
this workaround works
https://bugreports.qt.io/browse/QTBUG-64574
but make sure, to delay the reading after a orientation change
-
Hi @patrickkidd ,
-
Here is a sample code,which will return you the notch values:-
QPlatformWindow *platformWindow = static_cast<QPlatformWindow *>(window->handle());
QMargins margins = platformWindow->safeAreaMargins();
int topMargin = 0;
int bottomMorgin = 0;
int leftMargin = 0;
int rightMargin = 0;
topMargin = margins.top();
rightMargin = margins.right();
bottomMorgin = margins.bottom();
leftMargin = margins.left(); -
You need also need to set this:-
window.setFlag(Qt::MaximizeUsingFullscreenGeometryHint, true);
-
-
All very helpful and interesting responses.
Looks like
Qt.MaximizeUsingFullscreenGeometryHint
doesn't have an effect. I am using a QMainWindow for my top-level widget with no other flags set. -
@patrickkidd
if you're working with QWidgtes, and your TopMost Widget is a QMainWindow. Then simply set a Layout to the central widget.By default the layout respects the safe margins
-
@J.Hilk Can you paste a code snippet? When you say "set a Layout to the central widget," do you mean 1) layout the central widget as in my .ui file:
self.centralWidget = QtWidgets.QWidget(MainWindow) self.centralWidget.setObjectName("centralWidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralWidget)
or 2) lay out the QMainWindow and add the central widget:
self.ui.centralWidget = QOpenGLWidget(self) self.setCentralWidget(self.ui.centralWidget) Layout = QVBoxLayout(self) Layout.setContentsMargins(0, 0, 0, 0) Layout.addWidget(self.ui.centralWidget)
When I run #2 it gives the following warning and the app runs on Mac but only shows a white screen (within the safe zone) on iOS. There is no layout explicitly added so it must be implicit in QMainWindow:
kernel/qlayout.cpp(148): QLayout: Attempting to add QLayout "" to MainWindow "", which already has a layout
-
@patrickkidd
Sadly I have next to no experience with the python bindingsbut here's a simple c++ example (everything in main)
#include <QApplication> #include <QVBoxLayout> #include <QDebug> #include <QWidget> #include <QPainter> class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr) : QWidget(parent) { setStyleSheet("background-color:transparent;"); } ~Widget() = default; void setGridDistance(int distance) { m_GridDistance = distance; update(); } protected: void paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QPainter p(this); p.setPen(QPen(Qt::white,3)); for(int i(0); i < width(); i += m_GridDistance){ p.drawLine(i,0,i,height()); } for(int i(0); i < height(); i += m_GridDistance){ p.drawLine(0,i,width(),i); } } int m_GridDistance = 20; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget *w = new QWidget(); w->setStyleSheet("background-color:red;"); w->setWindowFlag(Qt::MaximizeUsingFullscreenGeometryHint,true); w->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea,false); w->showFullScreen(); Widget *wChild = new Widget(w); wChild->setStyleSheet("background-color:transparent;"); //!Does not work { QVBoxLayout *layout = new QVBoxLayout(w); layout->setSizeConstraint(QLayout::SetNoConstraint); layout->setMargin(0); layout->addWidget(wChild); } //!Works { // wChild->resize(w->size()); // wChild->show(); } return a.exec(); }
the normal QWidget spans the whole screen, the wChild widget only inside the save margins, due to the layout
Ignore the extra part, commended , parts IIRC that is for an other issue x)
-
@J.Hilk said in Has anyone worked around iOS safe zone margins, like with iPhone X?:
w->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea,false);
It looks like this was the line to do it. The
Qt::MaximizeUsingFullscreenGeometryHint
didn't have any effect. I didn't callshowFullScreen()
.So now it will just be a matter of getting the margins from QPlatformWindow using the example from the following if I can only figure out the include for QPlatformWindow. <qpa/qplatformwindow.h> doesn't seem to work:
QPlatformWindow *platformWindow = static_cast<QPlatformWindow *>(window->handle()); QMargins margins = platformWindow->safeAreaMargins();
Any idea what the include is for QPlatformWindow?
-
@patrickkidd said in Has anyone worked around iOS safe zone margins, like with iPhone X?:
Any idea what the include is for QPlatformWindow?
inside your *.pro file you need to include this module:
QT += gui-private
then this include is available:
#include <QtGui/qpa/qplatformwindow.h>
-
I didn't like too much the idea of using the private module, so this is how I implemented it: https://github.com/carlonluca/lqtutils/blob/master/lqtutils_ui.h#L55. Uses Objective-C++ on iOS and JNI on Android. More info: https://bugfreeblog.duckdns.org/2023/01/qt-qml-cutouts.html.