WebEngineView + 虚拟键盘 - 调整大小后保持滚动位置(集中输入)
WebEngineView + virtual keyboard - maintain scroll position after resizing (focused input)
我有一个非常简单的浏览器应用程序,它基于 WebEngineView 和用 Qt Quick 制作的虚拟键盘。
一切正常 - 每次我在 web 视图中单击输入时,键盘都会完美显示,但令我困扰的是,如果我单击底部的输入,键盘会在打开后覆盖它并我看不到我输入的内容。
我尝试通过调整 WebEngineView 元素的大小以适应键盘高度来解决此问题,就像大多数移动应用程序一样。它有效,我可以在键盘下滚动页面,但键盘仍然覆盖输入,我需要手动滚动。
有什么方法可以调整 Web 视图滚动位置,使键盘不覆盖来自 QML 的聚焦输入?
我无法在单个网站上执行此操作,因为我允许导航到用户想要的任何网站,因此我需要一些通用方法。
这是我的 qml 代码:
import QtQuick 2.12
import QtQuick.Window 2.12
import FreeVirtualKeyboard 1.0
import QtWebEngine 1.8
Window {
id: appContainer;
visible: true
width: 1280
height: 600
title: qsTr("WebEngineView")
property string pathUrl: "https://www.w3schools.com/html/html_forms.asp"
WebEngineView {
id: webview
width: appContainer.width
url: appContainer.pathUrl
height: appContainer.height
}
/*
Virtual keyboard
*/
InputPanel {
id: inputPanel
z: 99
y: appContainer.height
anchors.left: parent.left
anchors.right: parent.right
states: State {
name: "visible"
when: Qt.inputMethod.visible
PropertyChanges {
target: inputPanel
y: appContainer.height - inputPanel.height
}
}
transitions: Transition {
from: ""
to: "visible"
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 150
easing.type: Easing.InOutQuad
}
}
onRunningChanged: {
if(!running && inputPanel.state == "visible") {
// finished showing keyboard
webview.height = appContainer.height - inputPanel.height
console.log('Keyboard shown')
} else if(running && inputPanel.state != "visible") {
// begins to hide keyboard
webview.height = appContainer.height
console.log('Keyboard starts to hide');
}
}
}
}
}
到目前为止,调整大小部分工作正常 - 我在 onRunningChanged 中执行此操作,因此 webview 在过渡开始之前和结束之后调整大小 - 这可以防止在过渡期间显示丑陋的空白 space。
更新
在显示键盘后,我使用 webview.runJavaScript
和 scrollIntoView
达到了我想要的效果:
webview.runJavaScript("document.activeElement.scrollIntoView({block: 'nearest', inline: 'nearest', behavior: 'smooth'})");
但是我不确定这是否是最好的解决方案,因为我不喜欢在过程中涉及 javascript 评估这一事实。我想知道是否有更多的“本地”方式来执行此操作。
调整 WebEngineView 的大小,滚动到视图中
调整 WebEngineView
大小的问题是 HTML 会看到您的设备屏幕突然缩小,并可能决定呈现截然不同的布局,例如将菜单从顶部移动到屏幕的另一侧屏幕.
即使这没有发生,布局也发生了变化。新“屏幕”上的位置与旧“屏幕”上的位置不对应,没有 1:1 关系,这就是为什么它首先滚动到看似随机的位置。
我们可以tell webpage to scroll a focused element into view of new viewport:
- 如果它已经出现在屏幕上,那么什么也不会发生。
- 如果不是,则网页会滚动以使该元素尽可能适合屏幕。
scrollIntoView
具有根据需要滚动到屏幕 top/bottom 的参数
所以当屏幕键盘打开时:
- 保存原件
scrollPosition
- 调整大小
WebEngineView
- 可选择将
scrollPosition
分配给保存的值 - 尽管它可能对您没有任何好处
- 用
runJavaScript
确定activeElement
,使scrollIntoView
关闭屏幕键盘时重复相同的步骤。
不调整大小,手动滚动
另一种方法是不调整“屏幕”的大小,如果元素被覆盖,则将其滚动到视图中。
这需要 Qt 进行更改 VisualViewport
while leaving LayoutViewport
intact (see this and this 以获取更多信息)但似乎 Qt 无法做到这一点,至少不能单独通过 QML。
这让我们不得不手动完成:用 getBoundingClientRect
, calculate how much space does keyboard cover, and if it is not inside our calculated uncovered view area - scrollTo 确定位置。
(您仍然需要 runJavaScript
才能进入网页)
也许 this and this SO 问题可以提供帮助
其他选项
@Hazelnutek 报告说 document.activeElement.scrollIntoViewIfNeeded()
取得了一些成功
请参阅下面对此答案的评论中的讨论:
我有一个非常简单的浏览器应用程序,它基于 WebEngineView 和用 Qt Quick 制作的虚拟键盘。
一切正常 - 每次我在 web 视图中单击输入时,键盘都会完美显示,但令我困扰的是,如果我单击底部的输入,键盘会在打开后覆盖它并我看不到我输入的内容。
我尝试通过调整 WebEngineView 元素的大小以适应键盘高度来解决此问题,就像大多数移动应用程序一样。它有效,我可以在键盘下滚动页面,但键盘仍然覆盖输入,我需要手动滚动。
有什么方法可以调整 Web 视图滚动位置,使键盘不覆盖来自 QML 的聚焦输入? 我无法在单个网站上执行此操作,因为我允许导航到用户想要的任何网站,因此我需要一些通用方法。
这是我的 qml 代码:
import QtQuick 2.12
import QtQuick.Window 2.12
import FreeVirtualKeyboard 1.0
import QtWebEngine 1.8
Window {
id: appContainer;
visible: true
width: 1280
height: 600
title: qsTr("WebEngineView")
property string pathUrl: "https://www.w3schools.com/html/html_forms.asp"
WebEngineView {
id: webview
width: appContainer.width
url: appContainer.pathUrl
height: appContainer.height
}
/*
Virtual keyboard
*/
InputPanel {
id: inputPanel
z: 99
y: appContainer.height
anchors.left: parent.left
anchors.right: parent.right
states: State {
name: "visible"
when: Qt.inputMethod.visible
PropertyChanges {
target: inputPanel
y: appContainer.height - inputPanel.height
}
}
transitions: Transition {
from: ""
to: "visible"
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 150
easing.type: Easing.InOutQuad
}
}
onRunningChanged: {
if(!running && inputPanel.state == "visible") {
// finished showing keyboard
webview.height = appContainer.height - inputPanel.height
console.log('Keyboard shown')
} else if(running && inputPanel.state != "visible") {
// begins to hide keyboard
webview.height = appContainer.height
console.log('Keyboard starts to hide');
}
}
}
}
}
到目前为止,调整大小部分工作正常 - 我在 onRunningChanged 中执行此操作,因此 webview 在过渡开始之前和结束之后调整大小 - 这可以防止在过渡期间显示丑陋的空白 space。
更新
在显示键盘后,我使用 webview.runJavaScript
和 scrollIntoView
达到了我想要的效果:
webview.runJavaScript("document.activeElement.scrollIntoView({block: 'nearest', inline: 'nearest', behavior: 'smooth'})");
但是我不确定这是否是最好的解决方案,因为我不喜欢在过程中涉及 javascript 评估这一事实。我想知道是否有更多的“本地”方式来执行此操作。
调整 WebEngineView 的大小,滚动到视图中
调整 WebEngineView
大小的问题是 HTML 会看到您的设备屏幕突然缩小,并可能决定呈现截然不同的布局,例如将菜单从顶部移动到屏幕的另一侧屏幕.
即使这没有发生,布局也发生了变化。新“屏幕”上的位置与旧“屏幕”上的位置不对应,没有 1:1 关系,这就是为什么它首先滚动到看似随机的位置。
我们可以tell webpage to scroll a focused element into view of new viewport:
- 如果它已经出现在屏幕上,那么什么也不会发生。
- 如果不是,则网页会滚动以使该元素尽可能适合屏幕。
scrollIntoView
具有根据需要滚动到屏幕 top/bottom 的参数
所以当屏幕键盘打开时:
- 保存原件
scrollPosition
- 调整大小
WebEngineView
- 可选择将
scrollPosition
分配给保存的值 - 尽管它可能对您没有任何好处 - 用
runJavaScript
确定activeElement
,使scrollIntoView
关闭屏幕键盘时重复相同的步骤。
不调整大小,手动滚动
另一种方法是不调整“屏幕”的大小,如果元素被覆盖,则将其滚动到视图中。
这需要 Qt 进行更改 VisualViewport
while leaving LayoutViewport
intact (see this and this 以获取更多信息)但似乎 Qt 无法做到这一点,至少不能单独通过 QML。
这让我们不得不手动完成:用 getBoundingClientRect
, calculate how much space does keyboard cover, and if it is not inside our calculated uncovered view area - scrollTo 确定位置。
(您仍然需要 runJavaScript
才能进入网页)
也许 this and this SO 问题可以提供帮助
其他选项
@Hazelnutek 报告说 document.activeElement.scrollIntoViewIfNeeded()
请参阅下面对此答案的评论中的讨论: