Reputation: 1217
I am writing a chat application using Qt/QML. However, I found an issue while testing the application on my Android device: the virtual keyboard "moves" the window upward and does not allow me to see many of the displayed messages, only the bottom part of my app.
Ideally, I would like to resize the window so that both the message controls (such as the text box and attach files button) and the title bar to be shown. For a graphical example, you can take a look at this:
Is it possible to do this in QML?
Upvotes: 5
Views: 2935
Reputation: 16849
There is a QML-only way of reacting by resizing your window contents when the virtual keyboard is shown or hidden by the user.
First, make sure that the window resizing is not already done by Android for you (which is also possible). So you would tell Android that the keyboard should overlap the window, by adjusting the <activity>
tag in AndroidManifest.xml
as follows:
<activity ... android:windowSoftInputMode="adjustPan">
Then, you would place the following into a QML file where you have access to the window or window contents you want to resize and / or reposition:
Connections {
target: Qt.inputMethod
onKeyboardRectangleChanged: {
var newRect = Qt.inputMethod.keyboardRectangle
console.log(
"New keyboard rectangle size:" +
" x: " + newRect.x +
" y: " + newRect.y +
" width: " + newRect.width +
" height: " + newRect.height
)
// Your UI resizing / repositioning code goes here.
}
}
Explanations and details:
The Qt
QML Type is not instantiable (source), so you cannot write Qt { inputMethod.onKeyboardRectangleChanged: { }}
.
The Connections
QML type is made for these cases, allowing to implement a signal handler outside of the object emitting it (details).
Another alternative is to connect the signal to a JavaScript function with connect()
, as demonstrated here.
The QRectF
type used in the underlaying C++ class QInputMethod
is available in QML as QML Basic Type rect
. This is documented here:
When integrating with C++, note that any QRect or QRectF value passed into QML from C++ is automatically converted into a rect value, and vice-versa.
You should not implement this in a onVisibleChanged
signal handler because that event is not fired on Android when the user clicks the "hide keyboard" button. (Tested with Android 6.0 and Qt 5.12.) This seems to be a bug in Qt, since a keyboard of height 0 is definitely not visible.
Upvotes: 1
Reputation: 16849
You can tell Android to do this for you.
Android will resize your application window whenever the virtual keyboard shows up after you adjust the <activity>
tag of your AndroidManifest.xml
like this:
<activity ... android:windowSoftInputMode="adjustResize">
Source: This was discussed as a workaround in two comments on a Qt bug that prevented manually resizing the window for some time until the end of 2015.
Upvotes: 3
Reputation: 179
Deploying to Android 10 from Qt 5.12 (C++, no QML required). There don't seem to be any non-QML C++ examples out there of resizing an application in response to on-screen keyboard visibility changes. The ones I did find require interfacing w/ Java from Qt4.
It's necessary to create a container, separate from the QMainWindow, for all of your visible UI. QMainWindow normally occupies the entire screen and will be overlapped by the on-screen keyboard. The container QWidget is what can be resized and must contain every UI element you expect not to be under the keyboard.
The example uses QFrame as being a very minimal (lightweight) container.
YourApp.cpp:
YourApp::YourApp ( QWidget *parent ) : QMainWindow ( parent ) {
// With Android, an application running normally ...
// ... occupies the whole screen. Plan accordingly.
QSize availableSize = qApp->desktop()->availableGeometry().size();
Application_Width = availableSize.width();
Application_Height = availableSize.height();
App_Frame = new QFrame(this);
// Build your UI inside this QFrame
setCentralWidget(App_Frame);
Virtual_Keyboard_Enabled = true;
App_Input_Method = QApplication::inputMethod();
connect(App_Input_Method, SIGNAL(keyboardRectangleChanged()),
this, SLOT(onKeyboardRectangleChanged()));
this->show();
}
void
YourApp::onKeyboardRectangleChanged ( ) {
#if defined(Q_OS_ANDROID)
bool keyboard_visible = App_Input_Method->isVisible();
QRectF keyboard_rectangle = App_Input_Method->keyboardRectangle();
if (not keyboard_visible) {
App_Frame->resize(Application_Width, Application_Height);
}
else {
int keyboard_height = int(keyboard_rectangle.height());
App_Frame->resize(Application_Width,
(Application_Height - keyboard_height));
}
#endif
}
void
YourApp::Toggle_Virtual_Keyboard_Enabled ( ) {
#if defined(Q_OS_ANDROID)
Virtual_Keyboard_Enabled = not Virtual_Keyboard_Enabled;
App_Input_Method->setVisible(Virtual_Keyboard_Enabled);
qApp->setAutoSipEnabled(Virtual_Keyboard_Enabled);
#endif
}
YourApp.h:
class YourApp : public QMainWindow {
Q_OBJECT
public:
YourApp ( QWidget *parent = nullptr );
~YourApp ( );
private:
bool Virtual_Keyboard_Enabled;
QInputMethod *App_Input_Method;
QFrame *App_Frame;
void
Toggle_Virtual_Keyboard_Enabled ( );
private slots:
void
onKeyboardRectangleChanged ( );
}
Upvotes: 1