iOS: Simplify view management in QIOSKeyboardListener
We don't need to keep track of the view-controller or add ourselves as a gesture recognizer inside QIOSKeyboardListener. In fact, leaving the call to removeGestureRecognizer in [QIOSKeyboardListener dealloc] will result in QIOSKeyboardListener never being released, as the view that we add the recognizer to will keep a strong reference to the recognizer, so dealloc is never called unless the view is also released, which is unlikely to happen. We now fully control the lifetime of the recognizer. Change-Id: I6755e8cdfcc8f1062314db51aa54a2b7ecd1b967 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@theqtcompany.com>
This commit is contained in:
parent
c59c8ddf1f
commit
44e9e7fe19
@ -91,6 +91,8 @@ public:
|
||||
static QIOSInputContext *instance();
|
||||
|
||||
private:
|
||||
UIView* scrollableRootView();
|
||||
|
||||
union {
|
||||
QIOSKeyboardListener *m_keyboardHideGesture;
|
||||
id <KeyboardState> m_keyboardState;
|
||||
|
@ -45,6 +45,7 @@
|
||||
|
||||
#include "qiosglobal.h"
|
||||
#include "qiosintegration.h"
|
||||
#include "qiosscreen.h"
|
||||
#include "qiostextresponder.h"
|
||||
#include "qiosviewcontroller.h"
|
||||
#include "qioswindow.h"
|
||||
@ -76,8 +77,6 @@ static QUIView *focusView()
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@interface QIOSKeyboardListener : UIGestureRecognizer <KeyboardState, UIGestureRecognizerDelegate> {
|
||||
@public
|
||||
UIViewController *m_viewController;
|
||||
@private
|
||||
QIOSInputContext *m_context;
|
||||
}
|
||||
@ -97,26 +96,13 @@ static QUIView *focusView()
|
||||
{
|
||||
if (self = [super initWithTarget:self action:@selector(gestureStateChanged:)]) {
|
||||
m_context = context;
|
||||
m_viewController = 0;
|
||||
|
||||
if (isQtApplication()) {
|
||||
// Get the root view controller that is on the same screen as the keyboard:
|
||||
for (UIWindow *uiWindow in [[UIApplication sharedApplication] windows]) {
|
||||
if (uiWindow.screen == [UIScreen mainScreen]) {
|
||||
m_viewController = [uiWindow.rootViewController retain];
|
||||
break;
|
||||
}
|
||||
}
|
||||
Q_ASSERT(m_viewController);
|
||||
|
||||
// Attach 'hide keyboard' gesture to the window, but keep it disabled when the
|
||||
// keyboard is not visible.
|
||||
self.enabled = NO;
|
||||
self.cancelsTouchesInView = NO;
|
||||
self.delaysTouchesEnded = NO;
|
||||
[m_viewController.view.window addGestureRecognizer:self];
|
||||
}
|
||||
// UIGestureRecognizer
|
||||
self.enabled = NO;
|
||||
self.cancelsTouchesInView = NO;
|
||||
self.delaysTouchesEnded = NO;
|
||||
|
||||
/// KeyboardState
|
||||
self.keyboardVisible = NO;
|
||||
self.keyboardVisibleAndDocked = NO;
|
||||
self.animationDuration = 0;
|
||||
@ -141,9 +127,6 @@ static QUIView *focusView()
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[m_viewController.view.window removeGestureRecognizer:self];
|
||||
[m_viewController release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver:self
|
||||
name:@"UIKeyboardWillShowNotification" object:nil];
|
||||
@ -247,7 +230,7 @@ static QUIView *focusView()
|
||||
if (self.state != UIGestureRecognizerStatePossible)
|
||||
return;
|
||||
|
||||
CGPoint touchPoint = [[touches anyObject] locationInView:m_viewController.view.window];
|
||||
CGPoint touchPoint = [[touches anyObject] locationInView:self.view];
|
||||
if (CGRectContainsPoint(self.keyboardEndRect, touchPoint))
|
||||
self.state = UIGestureRecognizerStateBegan;
|
||||
}
|
||||
@ -349,14 +332,21 @@ QIOSInputContext::QIOSInputContext()
|
||||
, m_keyboardHideGesture([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
|
||||
, m_textResponder(0)
|
||||
{
|
||||
if (isQtApplication())
|
||||
if (isQtApplication()) {
|
||||
QIOSScreen *iosScreen = static_cast<QIOSScreen*>(QGuiApplication::primaryScreen()->handle());
|
||||
[iosScreen->uiWindow() addGestureRecognizer:m_keyboardHideGesture];
|
||||
|
||||
connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::cursorRectangleChanged);
|
||||
}
|
||||
|
||||
connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSInputContext::focusWindowChanged);
|
||||
}
|
||||
|
||||
QIOSInputContext::~QIOSInputContext()
|
||||
{
|
||||
[m_keyboardHideGesture.view removeGestureRecognizer:m_keyboardHideGesture];
|
||||
[m_keyboardHideGesture release];
|
||||
|
||||
[m_textResponder release];
|
||||
}
|
||||
|
||||
@ -398,6 +388,8 @@ QRectF QIOSInputContext::keyboardRect() const
|
||||
return m_keyboardState.keyboardRect;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
void QIOSInputContext::cursorRectangleChanged()
|
||||
{
|
||||
if (!m_keyboardState.keyboardVisibleAndDocked || !qApp->focusObject())
|
||||
@ -415,6 +407,18 @@ void QIOSInputContext::cursorRectangleChanged()
|
||||
prevCursor = cursor;
|
||||
}
|
||||
|
||||
UIView *QIOSInputContext::scrollableRootView()
|
||||
{
|
||||
if (!m_keyboardHideGesture.view)
|
||||
return 0;
|
||||
|
||||
UIWindow *window = static_cast<UIWindow*>(m_keyboardHideGesture.view);
|
||||
if (![window.rootViewController isKindOfClass:[QIOSViewController class]])
|
||||
return 0;
|
||||
|
||||
return window.rootViewController.view;
|
||||
}
|
||||
|
||||
void QIOSInputContext::scrollToCursor()
|
||||
{
|
||||
if (!isQtApplication())
|
||||
@ -427,24 +431,29 @@ void QIOSInputContext::scrollToCursor()
|
||||
return;
|
||||
}
|
||||
|
||||
UIView *view = m_keyboardHideGesture->m_viewController.view;
|
||||
if (view.window != focusView().window)
|
||||
UIView *rootView = scrollableRootView();
|
||||
if (!rootView)
|
||||
return;
|
||||
|
||||
if (rootView.window != focusView().window)
|
||||
return;
|
||||
|
||||
const int margin = 20;
|
||||
QRectF translatedCursorPos = qApp->inputMethod()->cursorRectangle();
|
||||
translatedCursorPos.translate(focusView().qwindow->geometry().topLeft());
|
||||
|
||||
qreal keyboardY = [view convertRect:m_keyboardState.keyboardEndRect fromView:nil].origin.y;
|
||||
qreal keyboardY = [rootView convertRect:m_keyboardState.keyboardEndRect fromView:nil].origin.y;
|
||||
int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y();
|
||||
|
||||
scroll((translatedCursorPos.bottomLeft().y() < keyboardY - margin) ? 0
|
||||
: qMin(view.bounds.size.height - keyboardY, translatedCursorPos.y() - statusBarY - margin));
|
||||
: qMin(rootView.bounds.size.height - keyboardY, translatedCursorPos.y() - statusBarY - margin));
|
||||
}
|
||||
|
||||
void QIOSInputContext::scroll(int y)
|
||||
{
|
||||
UIView *rootView = m_keyboardHideGesture->m_viewController.view;
|
||||
UIView *rootView = scrollableRootView();
|
||||
if (!rootView)
|
||||
return;
|
||||
|
||||
CATransform3D translationTransform = CATransform3DMakeTranslation(0.0, -y, 0.0);
|
||||
if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform))
|
||||
|
@ -63,6 +63,7 @@ public:
|
||||
void setOrientationUpdateMask(Qt::ScreenOrientations mask);
|
||||
|
||||
UIScreen *uiScreen() const;
|
||||
UIWindow *uiWindow() const;
|
||||
|
||||
void updateProperties();
|
||||
|
||||
|
@ -321,6 +321,11 @@ UIScreen *QIOSScreen::uiScreen() const
|
||||
return m_uiScreen;
|
||||
}
|
||||
|
||||
UIWindow *QIOSScreen::uiWindow() const
|
||||
{
|
||||
return m_uiWindow;
|
||||
}
|
||||
|
||||
#include "moc_qiosscreen.cpp"
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
Loading…
Reference in New Issue
Block a user