我正在使用 Qt/QML 编写一个聊天应用程序。但是,我在 Android 设备上测试应用程序时发现了一个问题:虚拟键盘将窗口向上“移动”,并且不允许我看到许多显示的消息,只能看到应用程序的底部。
理想情况下,我想调整窗口大小,以便显示消息控件(例如文本框和附加文件按钮)和标题栏。对于图形示例,您可以看一下:
。
可以在 QML 中执行此操作吗?
从 Qt 5.12 部署到 Android 10(C++,无需 QML)。似乎没有任何非 QML C++ 示例可以调整应用程序大小以响应屏幕键盘可见性变化。我发现的那些需要与 Qt4 中的 Java 进行交互。
有必要为所有可见 UI 创建一个与 QMainWindow 分开的容器。 QMainWindow 通常占据整个屏幕,并与屏幕键盘重叠。容器 QWidget 是可以调整大小的,并且必须包含您期望不在键盘下的每个 UI 元素。
该示例使用 QFrame 作为一个非常小的(轻量级)容器。
你的应用程序.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
}
你的应用程序.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 ( );
}
这篇文章解释了当 Android 虚拟键盘出现时调整 QML 控件大小的方法。它涉及使用一些java代码,但您可以直接复制并粘贴链接的项目示例提供的代码:
当用户显示或隐藏虚拟键盘时,有一种仅 QML 的反应方式,即调整窗口内容的大小。
首先,确保 Android 尚未为您完成窗口大小调整(这也是可能的)。因此,您可以通过调整
<activity>
中的 AndroidManifest.xml
标签来告诉 Android 键盘应该与窗口重叠,如下所示:
<activity ... android:windowSoftInputMode="adjustPan">
然后,您可以将以下内容放入 QML 文件中,您可以在其中访问要调整大小和/或重新定位的窗口或窗口内容:
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.
}
}
说明和细节:
Qt
QML 类型不可实例化(source),因此您无法编写Qt { inputMethod.onKeyboardRectangleChanged: { }}
。
Connections
QML 类型是为这些情况而设计的,允许在发出信号的对象之外实现信号处理程序(详细信息)。
另一种选择是使用
connect()
将信号连接到 JavaScript 函数,如此处所示。
底层 C++ 类中使用的
QRectF
类型 QInputMethod
在 QML 中可用作 QML 基本类型 rect
。这已记录在here:
与 C++ 集成时,请注意,从 C++ 传递到 QML 的任何 QRect 或 QRectF 值都会自动转换为矩形值,反之亦然。
您不应该在
onVisibleChanged
信号处理程序中实现此功能,因为当用户单击“隐藏键盘”按钮时,该事件在 Android 上不会触发。 (使用 Android 6.0 和 Qt 5.12 进行测试。)这似乎是 Qt 中的一个错误,因为高度 0 的键盘绝对不可见。
TextArea {
//..
//.. works with Qt 6.5.0 on iOS
//..
Connections {
target: Qt.inputMethod
function 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.
}
}
}
Qt 文档链接: