iOS: Center IM cursor rectangle within available space when showing keyboard
The cursor rectangle is translated into screen coordinates, and compared against the screen geometry after subtracting the future keyboard rect (which is already in screen coordinates). If the two do not overlap completely, the root view is shifted accordingly so that the cursor rectangle is placed in the center of the available space. A future improvement would be to first check if centering the input item's clip rectangle would bring the cursor within the available geometry, before falling back to using the cursor rectangle. This would look better for multi-line text inputs where the cursor is not in the center. Task-number: QTBUG-46747 Change-Id: If9b551b4d297e2a1f6d7f84b81628fa65c08edfd Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
parent
34f82b8abc
commit
3c99bddb84
@ -498,15 +498,32 @@ void QIOSInputContext::scrollToCursor()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int margin = 20;
|
QWindow *focusWindow = qApp->focusWindow();
|
||||||
QRectF translatedCursorPos = qApp->inputMethod()->cursorRectangle();
|
QRect cursorRect = qApp->inputMethod()->cursorRectangle().translated(focusWindow->geometry().topLeft()).toRect();
|
||||||
translatedCursorPos.translate(focusView().qwindow->geometry().topLeft());
|
if (cursorRect.isNull()) {
|
||||||
|
scroll(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qreal keyboardY = [rootView convertRect:m_keyboardState.keyboardEndRect fromView:nil].origin.y;
|
// Add some padding so that the cusor does not end up directly above the keyboard
|
||||||
int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y();
|
static const int kCursorRectPadding = 20;
|
||||||
|
cursorRect.adjust(0, -kCursorRectPadding, 0, kCursorRectPadding);
|
||||||
|
|
||||||
scroll((translatedCursorPos.bottomLeft().y() < keyboardY - margin) ? 0
|
// We explicitly ask for the geometry of the screen instead of the availableGeometry,
|
||||||
: qMin(rootView.bounds.size.height - keyboardY, translatedCursorPos.y() - statusBarY - margin));
|
// as we hide the statusbar when scrolling the screen, so the available geometry will
|
||||||
|
// include the space taken by the status bar at the moment.
|
||||||
|
QRect screenGeometry = focusWindow->screen()->geometry();
|
||||||
|
QRect keyboardGeometry = QRectF::fromCGRect(m_keyboardState.keyboardEndRect).toRect();
|
||||||
|
QRect availableGeometry = (QRegion(screenGeometry) - keyboardGeometry).boundingRect();
|
||||||
|
|
||||||
|
if (!availableGeometry.contains(cursorRect, true)) {
|
||||||
|
qImDebug() << "cursor rect" << cursorRect << "not fully within" << availableGeometry;
|
||||||
|
int scrollToCenter = -(availableGeometry.center() - cursorRect.center()).y();
|
||||||
|
int scrollToBottom = focusWindow->screen()->geometry().bottom() - availableGeometry.bottom();
|
||||||
|
scroll(qMin(scrollToCenter, scrollToBottom));
|
||||||
|
} else {
|
||||||
|
scroll(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QIOSInputContext::scroll(int y)
|
void QIOSInputContext::scroll(int y)
|
||||||
@ -519,6 +536,8 @@ void QIOSInputContext::scroll(int y)
|
|||||||
if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform))
|
if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
qImDebug() << "scrolling root view to y =" << -y;
|
||||||
|
|
||||||
QPointer<QIOSInputContext> self = this;
|
QPointer<QIOSInputContext> self = this;
|
||||||
[UIView animateWithDuration:m_keyboardState.animationDuration delay:0
|
[UIView animateWithDuration:m_keyboardState.animationDuration delay:0
|
||||||
options:(m_keyboardState.animationCurve << 16) | UIViewAnimationOptionBeginFromCurrentState
|
options:(m_keyboardState.animationCurve << 16) | UIViewAnimationOptionBeginFromCurrentState
|
||||||
|
Loading…
Reference in New Issue
Block a user