Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resize QML window when the virtual keyboard is shown

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:

screenshot of UI with keyboard shown.

Is it possible to do this in QML?

like image 624
Alex Spataru Avatar asked Sep 30 '22 22:09

Alex Spataru


2 Answers

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.

like image 117
tanius Avatar answered Oct 05 '22 00:10

tanius


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 ( );
}
like image 31
kcrossen Avatar answered Oct 04 '22 22:10

kcrossen