iOS: Change show() to imply maximize, and showFullScreen() to hide status bar

Matches the Android behavior, and gives an easy and predictable way to
show true fullscreen windows that is similar to how one would do it on
a desktop platform.

We keep the statusbar visibility in sync with the window state of the
active window.

Change-Id: Ia4b99e03f83e19f9ef56cc99b9d477cc6da4c734
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
This commit is contained in:
Tor Arne Vestbø 2013-11-21 11:25:48 +01:00 committed by The Qt Project
parent ae5392a00b
commit f441d8e523
8 changed files with 109 additions and 6 deletions

View File

@ -58,6 +58,22 @@
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.rootViewController = [[[QIOSViewController alloc] init] autorelease];
QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion;
// We prefer to keep the root viewcontroller in fullscreen layout, so that
// we don't have to compensate for the viewcontroller position. This also
// gives us the same behavior on iOS 5/6 as on iOS 7, where full screen layout
// is the only way.
if (iosVersion < QSysInfo::MV_IOS_7_0)
self.window.rootViewController.wantsFullScreenLayout = YES;
// Use translucent statusbar by default on iOS6 (unless the user changed the
// default in the Info.plist), so that windows placed under the stausbar are
// still visible, just like on iOS7.
if (iosVersion >= QSysInfo::MV_IOS_6_0 && iosVersion < QSysInfo::MV_IOS_7_0
&& [UIApplication sharedApplication].statusBarStyle == UIStatusBarStyleDefault)
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];
self.window.hidden = NO;
return YES;

View File

@ -160,7 +160,7 @@ QPlatformServices *QIOSIntegration::services() const
QVariant QIOSIntegration::styleHint(StyleHint hint) const
{
switch (hint) {
case ShowIsFullScreen:
case ShowIsMaximized:
return true;
case SetFocusOnTouchRelease:
return true;

View File

@ -50,8 +50,10 @@
QT_BEGIN_NAMESPACE
class QIOSScreen : public QPlatformScreen
class QIOSScreen : public QObject, public QPlatformScreen
{
Q_OBJECT
public:
QIOSScreen(unsigned int screenIndex);
~QIOSScreen();
@ -75,6 +77,9 @@ public:
void updateProperties();
void layoutWindows();
public slots:
void updateStatusBarVisibility();
private:
UIScreen *m_uiScreen;
QRect m_geometry;

View File

@ -139,6 +139,8 @@ QIOSScreen::QIOSScreen(unsigned int screenIndex)
m_unscaledDpi = 163; // Regular iPhone DPI
}
connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSScreen::updateStatusBarVisibility);
updateProperties();
}
@ -185,6 +187,31 @@ void QIOSScreen::updateProperties()
layoutWindows();
}
void QIOSScreen::updateStatusBarVisibility()
{
QWindow *focusWindow = QGuiApplication::focusWindow();
// If we don't have a focus window we leave the status
// bar as is, so that the user can activate a new window
// with the same window state without the status bar jumping
// back and forth.
if (!focusWindow)
return;
UIView *view = reinterpret_cast<UIView *>(focusWindow->handle()->winId());
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0) {
[view.viewController setNeedsStatusBarAppearanceUpdate];
} else
#endif
{
QIOSViewController *viewController = static_cast<QIOSViewController *>(view.viewController);
[[UIApplication sharedApplication]
setStatusBarHidden:[viewController prefersStatusBarHidden]
withAnimation:UIStatusBarAnimationNone];
}
}
void QIOSScreen::layoutWindows()
{
QList<QWindow*> windows = QGuiApplication::topLevelWindows();
@ -273,4 +300,6 @@ UIScreen *QIOSScreen::uiScreen() const
return m_uiScreen;
}
#include "moc_qiosscreen.cpp"
QT_END_NAMESPACE

View File

@ -42,5 +42,6 @@
#import <UIKit/UIKit.h>
@interface QIOSViewController : UIViewController
- (BOOL)prefersStatusBarHidden;
@end

View File

@ -42,9 +42,11 @@
#import "qiosviewcontroller.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtGui/QScreen>
#include "qiosscreen.h"
#include "qiosglobal.h"
#include "qioswindow.h"
@implementation QIOSViewController
@ -74,5 +76,28 @@
qiosScreen->updateProperties();
}
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0)
- (UIStatusBarStyle)preferredStatusBarStyle
{
// Since we don't place anything behind the status bare by default, we
// end up with a black area, so we have to enable the white text mode
// of the iOS7 statusbar.
return UIStatusBarStyleLightContent;
// FIXME: Try to detect the content underneath the statusbar and choose
// an appropriate style, and/or expose Qt APIs to control the style.
}
#endif
- (BOOL)prefersStatusBarHidden
{
QWindow *focusWindow = QGuiApplication::focusWindow();
if (!focusWindow)
return [UIApplication sharedApplication].statusBarHidden;
QIOSWindow *topLevel = static_cast<QIOSWindow *>(focusWindow->handle())->topLevelWindow();
return topLevel->window()->windowState() == Qt::WindowFullScreen;
}
@end

View File

@ -85,6 +85,8 @@ public:
WId winId() const { return WId(m_view); };
QIOSWindow *topLevelWindow() const;
private:
void applyGeometry(const QRect &rect);

View File

@ -456,6 +456,10 @@ void QIOSWindow::setVisible(bool visible)
if (visible) {
requestActivateWindow();
if (window()->isTopLevel())
static_cast<QIOSScreen *>(screen())->updateStatusBarVisibility();
} else {
// Activate top-most visible QWindow:
NSArray *subviews = m_view.viewController.view.subviews;
@ -530,10 +534,6 @@ void QIOSWindow::applyGeometry(const QRect &rect)
void QIOSWindow::setWindowState(Qt::WindowState state)
{
// FIXME: Figure out where or how we should disable/enable the statusbar.
// Perhaps setting QWindow to maximized should also mean that we'll show
// the statusbar, and vice versa for fullscreen?
switch (state) {
case Qt::WindowNoState:
applyGeometry(m_normalGeometry);
@ -552,6 +552,14 @@ void QIOSWindow::setWindowState(Qt::WindowState state)
default:
Q_UNREACHABLE();
}
if (window()->isTopLevel() && window()->isVisible() && window()->isActive()) {
// The window state of the QWindow is not updated until after
// we return from this method, so we have to defer any updates
// of the statusbar that depend on the current window state.
QMetaObject::invokeMethod(static_cast<QIOSScreen *>(screen()),
"updateStatusBarVisibility", Qt::QueuedConnection);
}
}
void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
@ -569,6 +577,23 @@ void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
}
}
QIOSWindow *QIOSWindow::topLevelWindow() const
{
QWindow *window = this->window();
while (window) {
QWindow *parent = window->parent();
if (!parent)
parent = window->transientParent();
if (!parent)
break;
window = parent;
}
return static_cast<QIOSWindow *>(window->handle());
}
void QIOSWindow::requestActivateWindow()
{
// Note that several windows can be active at the same time if they exist in the same