【问题标题】:iOS: Sometimes Keyboard pushes up the whole qml pageiOS:有时键盘会向上推整个 qml 页面
【发布时间】:2016-01-11 07:48:12
【问题描述】:

我正在开发一个跨平台的 QML QtQuick 应用程序。一个窗口是典型的聊天,下面有标题、消息区域和 TextEdit 输入。在 iOS 上(在模拟器和真实设备中)我遇到了虚拟键盘的问题,它“移动”了文本编辑以及整个窗口向上并且不允许看到标题。

这是应用程序窗口的截图:https://drive.google.com/file/d/0B6ZI4g3F2MLOSXB2RjBDbGNEWEk

相同的issue 已在 Qt 错误跟踪器中注册。但是没有解决办法。而且,论坛上也有人报告过类似的问题,没有人回答。

关于解决方案或解决方法的任何想法?

【问题讨论】:

  • 你能找到这个问题的任何例子吗,.. 2年后,仍然是同样的问题。如果是,请指导,提前谢谢

标签: ios qt keyboard qml


【解决方案1】:

我过去曾实施过一项工作,但确实存在问题。

避免使用键盘是一种痛苦,Qt 滚动整个屏幕的单一尺寸方法并不理想(尤其是当它有问题且禁用时很痛苦),导致导航栏移出屏幕等。

基本上,我的工作是:

  • 添加一个MouseArea 作为TextField 的子项,这将停止设置焦点并停止默认滚动行为
  • 在该MouseAreaonClick 处理程序中,移动该字段,使其不在出现键盘的区域下方。这可以使用例如状态和行为动画来完成
  • 当动画停止时,将焦点显式设置到文本字段,这将导致键盘出现(但屏幕不会滚动,因为您已将焦点元素移开)

让这些东西很好地制作动画可能会很痛苦。此外,您可以在某种程度上对键盘的大小进行硬编码,但需要借助 ObjC 来获取实际的键盘高度(并通过某些属性将其暴露给 QML)。

反面,即键盘关闭,也可能是一种痛苦。需要处理文本字段失去焦点、用户点击空白、用户点击关闭键(在 iPad 上)等。结帐Qt.inputmethod

在 Qt 的辩护中,避免键盘是很难做到的,需要了解应用程序布局才能获得最佳效果。这就是为什么 UIKit 实际上根本不处理它的原因(除非它可以知道要滚动什么以及滚动多少,例如表格)。

【讨论】:

  • 能否为您的解决方法提供一些代码:-)?
【解决方案2】:

iOS 上的 QTextEdit 也有类似的问题。当 QTextEdit 在虚拟键盘下时,整个窗口向上移动。我查看了 qt 代码,发现当 inputMethodQuery 属性 Qt::ImCursorRectangle 返回的值位于虚拟键盘下方时,qt 将小部件向上移动。我通过为属性 Qt::ImCursorRectangle 返回无效的 QRectF 来解决窗口向上移动

QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
{
    if (property & Qt::ImCursorRectangle) {
        return QVariant(QRectF(0,0, 0, 0));
    } else {
        return QTextEdit::inputMethodQuery(property);
    }
}

【讨论】:

    【解决方案3】:

    根据user2632422 的回答,我实现了一个适用于 QML 项目的解决方法。这个想法是在 QQuickItem 上安装一个事件过滤器,并用Qt::InputMethodQuery::ImCursorRectangle 监听QEvent::InputMethodQuery。然后我们将其值设置为空 QRectF 并且 Qt 将不再滚动视图以显示该文本字段。

    我假设您知道如何将 C++ 类公开给 QML(如果不知道,请查看 here

    在 C++ 中准备一个类并将其公开给 QML:

    class Api : public QObject {
    Q_OBJECT
    ....
    public:
        Q_INVOKABLE void setupImEventFilter(QQuickItem *item) {
            static thread_local ImFixer imf;
            item->installEventFilter(&imf);
        }
    }
    
    // somewhere in main(): view.rootContext()->setContextProperty("api", new Api());
    

    我们也需要实际的事件过滤器:

    class ImFixer : public QObject {
        Q_OBJECT
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override {
            if (event->type() == QEvent::InputMethodQuery) {
                QInputMethodQueryEvent *imEvt = static_cast<QInputMethodQueryEvent *>(event);
                if (imEvt->queries() == Qt::InputMethodQuery::ImCursorRectangle) {
                    imEvt->setValue(Qt::InputMethodQuery::ImCursorRectangle, QRectF());
                    return true;
                }
            }
            return QObject::eventFilter(obj, event);
        }
    };
    

    最后在QML中添加:

    TextField {
        id: tf;
    ...
        Component.onCompleted: api.setupImEventFilter(tf);
    }
    
    

    QTBUG-80790 也跟踪了此问题,因此希望它会添加到未来的 Qt 版本中。

    【讨论】:

      猜你喜欢
      • 2014-08-14
      • 2017-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-26
      • 1970-01-01
      • 1970-01-01
      • 2020-12-29
      相关资源
      最近更新 更多