WebEngineView + 虚拟键盘 - 调整大小后保持滚动位置(重点输入)
Posted
技术标签:
【中文标题】WebEngineView + 虚拟键盘 - 调整大小后保持滚动位置(重点输入)【英文标题】:WebEngineView + virtual keyboard - maintain scroll position after resizing (focused input) 【发布时间】:2021-03-05 08:56:44 【问题描述】:我有一个基于 WebEngineView 和 Qt Quick 虚拟键盘的非常简单的浏览器应用程序。
一切正常 - 每次单击 web 视图中的输入时,键盘都会完美显示,但令我困扰的是,如果我单击底部的输入,键盘会在打开后覆盖它,我不能看看我在输入什么。
我尝试通过调整 WebEngineView 元素的大小以适应键盘高度来解决这个问题,就像大多数移动应用程序一样。有效,我可以在键盘下滚动页面,但键盘仍然覆盖输入,我需要手动滚动。
有什么方法可以调整网页视图的滚动位置,使键盘不会覆盖来自 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 在转换开始之前和结束之后调整大小 - 这可以防止在转换期间显示丑陋的空白空间。
更新
用webview.runjavascript
和scrollIntoView
在显示键盘后达到了我想要的效果:
webview.runJavaScript("document.activeElement.scrollIntoView(block: 'nearest', inline: 'nearest', behavior: 'smooth')");
但是我不确定这是否是最好的解决方案,因为我不喜欢将 javascript 评估纳入流程的事实。我想知道是否还有其他“本地”方式可以做到这一点。
【问题讨论】:
【参考方案1】:调整 WebEngineView 的大小,滚动到视图中
调整WebEngineView
大小的问题在于,HTML 会看到您的设备屏幕突然缩小,并可能决定呈现截然不同的布局,例如将菜单从屏幕顶部移动到屏幕的一侧。
即使这没有发生,布局也发生了变化。新“屏幕”上的位置与旧“屏幕”上的位置不对应,没有 1:1 的关系,这就是为什么它首先滚动到一个看似随机的位置。
我们可以tell webpage 到scroll a focused element into view of new viewport:
如果它已经在屏幕上,那么什么都不会发生。 如果没有,网页会滚动以使元素尽可能适合屏幕。scrollIntoView
具有根据需要滚动到屏幕顶部/底部的参数
所以当屏幕键盘打开时:
-
保存原图
scrollPosition
调整大小WebEngineView
(可选)将 scrollPosition
分配给保存的值 - 尽管它可能对您没有任何好处
使用runJavaScript
确定activeElement
并使其成为scrollIntoView
当屏幕键盘关闭时重复相同的步骤。
不要调整大小,手动滚动
另一种方法是不调整“屏幕”的大小,如果元素被覆盖,只需将其滚动到视图中。
这需要 Qt 更改 VisualViewport
,同时保持 LayoutViewport
不变(有关更多信息,请参阅 this 和 this),但似乎 Qt 无法做到这一点,至少不能仅通过 QML。
这让我们不得不手动进行:使用getBoundingClientRect
确定位置,计算键盘覆盖了多少空间,如果它不在我们计算的未覆盖视图区域内 - scrollTo 它。
(您仍然需要runJavaScript
才能进入网页)
也许this 和this 这样的问题会有所帮助
其他选项
@Hazelnutek 报告了document.activeElement.scrollIntoViewIfNeeded()
的一些成功
请参阅下面 cmets 中对此答案的讨论:
【讨论】:
我采用了第一种方法(调整大小)——但我注意到了一个问题。 scrollIntoView 函数似乎有点错误,并且在某些类型的网站上(我认为全屏网站没有任何实际滚动)调用它实际上会移动整个视口,并且在键盘关闭后它不会返回。因此我想要更好的东西,但我认为scrollTo
在没有实际滚动行为的页面上根本不起作用?需要做transform: translate..
之类的事情吗?
QML 的transform: translate
可能不起作用,因为我认为 QML 没有这种对 webkit 页面画布的访问权限。而是尝试在有问题的页面上设置 scrollPosition
( doc.qt.io/qt-5/… ) - 它有效吗?如果没有,可能需要一些 javascript hack - 这远远超出了我的专业知识。这个问题可能不是 Qt 特有的,所以问另一个问题,例如“我如何滚动一个不可滚动的网站?”带有javascript
、webpage
等标签,列出违规网站,附上你的javascript代码。
如果您的主要问题只是关闭键盘后页面没有回滚,您可以尝试使用 window.scrollY
( developer.mozilla.org/en-US/docs/Web/API/Window/scrollY ) 保存当前位置,然后使用 window.scroll()
和保存的号码,或者您可以尝试保存和设置上述 QML 的scrollPosition
。实验。看看有没有什么工作至少在某种程度上。另请注意,您可以使用userScripts
属性(doc.qt.io/qt-5/…)将任何 javascript 注入网页
尚未测试,但我猜scrollPosition
只有在整个视口可滚动时才有效,但有些网站是全屏的,当显示键盘时,它们的全部内容必须移动。 scrollIntoView
会这样做,但有时会出现错误并使视口向上移动。我在键盘关闭(焦点改变)后再次调用document.activeElement.scrollIntoViewIfNeeded(...)
解决了这个问题。工作至今。我认为只要只改变高度而不改变宽度,就css响应性而言,调整大小不应该是坏事
如果您的问题得到解决,请接受此答案或添加您的答案以及有效方法的简短描述并接受。这会将您的问题标记为不需要更多答案。谢谢。以上是关于WebEngineView + 虚拟键盘 - 调整大小后保持滚动位置(重点输入)的主要内容,如果未能解决你的问题,请参考以下文章