带背景的 Qt QML SwipeView,如何在页面移动时模糊正确的区域?
Qt QML SwipeView w/ background, how can I blur the right region as the page moves?
我有一个带背景图片的 SwipeView。它有两个页面,两个页面都有一组控件和文本,我在它们下面放了一个类似 iOS 的模糊圆角矩形,这样它更容易阅读,但不会完全遮挡漂亮的背景
我在这个线程的末尾发现了这个片段,它让我使用了一个白色矩形和一个半透明的 FastBlur 来对背景进行采样:https://forum.qt.io/topic/38297/a-semi-transparent-rectangle-that-also-blurs/7
Rectangle {
anchors.fill: fastBlur
color: "white"
}
FastBlur {
id: fastBlur
height: 124
width: parent.width
radius: 40
opacity: 0.55
source: ShaderEffectSource {
sourceItem: flickable
sourceRect: Qt.rect(0, 0, fastBlur.width, fastBlur.height)
}
}
当我移动到 SwipeView 中的下一页时,背景保持静态但模糊没有,当然,因为 sourceRect 区域没有相对于其父级移动,只是父级正在移动相对于背景。模糊仍在从其原始位置采样背景,而不是在它通过滑动视图移动时的新位置
所以我发现我可以获得 SwipeView.contentItem.contentX 的事实(感谢 的回答!)但是在我的两个页面中,我必须以不同的方式考虑基于 contentX 的内容他们的顺序是什么
我在这里设置了一个示例模糊项目来说明我的意思。 https://github.com/ftab/BlurTest
具体来说,在 sourceRect - https://github.com/ftab/BlurTest/blob/master/Page1Form.qml#L23
sourceRect: Qt.rect(
fastBlur.x - swipeView.contentItem.contentX,
fastBlur.y,
fastBlur.width,
fastBlur.height)
当它在背景中移动时,这会获得模糊更新的预期效果,但仅在模糊区域位于滑动视图的第一页并且 contentX 从 0 变为 640 时才起作用。如果这是在第二页,我必须做 640 - contentX + fastBlur.x,然后如果我再次移动它,我必须再次调整它,等等
有没有更好的方法来做到这一点,或者每当我添加另一个页面或更改顺序时,我几乎都无法手动编辑 sourceRect?
编辑:完整的 QML 文件,例如 3 页:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import QtGraphicalEffects 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
background: Image {
id: imgBackground
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: "nature_1.jpg"
}
Item {
id: item1
Rectangle {
id: recFrost
anchors.fill: fastBlur
color: "white"
}
FastBlur {
id: fastBlur
anchors.fill: recControls
source: ShaderEffectSource {
sourceItem: imgBackground
sourceRect: Qt.rect(
fastBlur.x - swipeView.contentItem.contentX,
fastBlur.y,
fastBlur.width,
fastBlur.height)
}
radius: 32
opacity: 0.55
}
Rectangle {
id: recControls
width: 364
height: 89
color: "#00000000"
anchors.bottomMargin: 8
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
Label {
text: qsTr("First page")
anchors.centerIn: parent
}
}
}
Item {
id: item2
Rectangle {
id: recFrost2
anchors.fill: fastBlur2
color: "white"
}
FastBlur {
id: fastBlur2
anchors.fill: recControls2
source: ShaderEffectSource {
sourceItem: imgBackground
sourceRect: Qt.rect(
swipeView.width - swipeView.contentItem.contentX + fastBlur2.x,
fastBlur2.y,
fastBlur2.width,
fastBlur2.height)
}
radius: 32
opacity: 0.55
}
Rectangle {
id: recControls2
width: 364
height: 89
color: "#00000000"
anchors.centerIn: parent
Label {
text: qsTr("Second page")
anchors.centerIn: parent
}
}
}
Item {
id: item3
Rectangle {
id: recFrost3
anchors.fill: fastBlur3
color: "white"
}
FastBlur {
id: fastBlur3
anchors.fill: recControls3
source: ShaderEffectSource {
sourceItem: imgBackground
sourceRect: Qt.rect(
swipeView.width * 2 - swipeView.contentItem.contentX + fastBlur2.x,
fastBlur3.y,
fastBlur3.width,
fastBlur3.height)
}
radius: 32
opacity: 0.55
}
Rectangle {
id: recControls3
width: 364
height: 89
color: "#00000000"
anchors.topMargin: 8
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
Label {
text: qsTr("Third page")
anchors.centerIn: parent
}
}
}
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
TabButton {
text: qsTr("First")
}
TabButton {
text: qsTr("Second")
}
TabButton {
text: qsTr("Third")
}
}
}
您可以使用父页面在 SwipeView
中的 x
位置代替 swipeView.width
增量:
sourceRect: Qt.rect(fastBlur2.x - swipeView.contentItem.contentX + item2.x,
fastBlur2.y,
fastBlur2.width,
astBlur2.height)
或者您可以 Item
的 mapToItem()
。
然而,由于 mapToItem
是一个函数,当一个项目相对于另一个项目移动时,使用它的 return 值不会触发绑定更新,我们必须温和地提示 QML 引擎何时重新评估绑定。
sourceRect: {
swipeView.contentItem.contentX; /*here we access contentX in order to
force the reevaluation of the entire expression when contentX changes.*/
return fastBlur3.mapToItem(swipeView, 0, 0, fastBlur3.width, fastBlur3.height);
}
我有一个带背景图片的 SwipeView。它有两个页面,两个页面都有一组控件和文本,我在它们下面放了一个类似 iOS 的模糊圆角矩形,这样它更容易阅读,但不会完全遮挡漂亮的背景
我在这个线程的末尾发现了这个片段,它让我使用了一个白色矩形和一个半透明的 FastBlur 来对背景进行采样:https://forum.qt.io/topic/38297/a-semi-transparent-rectangle-that-also-blurs/7
Rectangle {
anchors.fill: fastBlur
color: "white"
}
FastBlur {
id: fastBlur
height: 124
width: parent.width
radius: 40
opacity: 0.55
source: ShaderEffectSource {
sourceItem: flickable
sourceRect: Qt.rect(0, 0, fastBlur.width, fastBlur.height)
}
}
当我移动到 SwipeView 中的下一页时,背景保持静态但模糊没有,当然,因为 sourceRect 区域没有相对于其父级移动,只是父级正在移动相对于背景。模糊仍在从其原始位置采样背景,而不是在它通过滑动视图移动时的新位置
所以我发现我可以获得 SwipeView.contentItem.contentX 的事实(感谢
我在这里设置了一个示例模糊项目来说明我的意思。 https://github.com/ftab/BlurTest
具体来说,在 sourceRect - https://github.com/ftab/BlurTest/blob/master/Page1Form.qml#L23
sourceRect: Qt.rect(
fastBlur.x - swipeView.contentItem.contentX,
fastBlur.y,
fastBlur.width,
fastBlur.height)
当它在背景中移动时,这会获得模糊更新的预期效果,但仅在模糊区域位于滑动视图的第一页并且 contentX 从 0 变为 640 时才起作用。如果这是在第二页,我必须做 640 - contentX + fastBlur.x,然后如果我再次移动它,我必须再次调整它,等等
有没有更好的方法来做到这一点,或者每当我添加另一个页面或更改顺序时,我几乎都无法手动编辑 sourceRect?
编辑:完整的 QML 文件,例如 3 页:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import QtGraphicalEffects 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
background: Image {
id: imgBackground
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: "nature_1.jpg"
}
Item {
id: item1
Rectangle {
id: recFrost
anchors.fill: fastBlur
color: "white"
}
FastBlur {
id: fastBlur
anchors.fill: recControls
source: ShaderEffectSource {
sourceItem: imgBackground
sourceRect: Qt.rect(
fastBlur.x - swipeView.contentItem.contentX,
fastBlur.y,
fastBlur.width,
fastBlur.height)
}
radius: 32
opacity: 0.55
}
Rectangle {
id: recControls
width: 364
height: 89
color: "#00000000"
anchors.bottomMargin: 8
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
Label {
text: qsTr("First page")
anchors.centerIn: parent
}
}
}
Item {
id: item2
Rectangle {
id: recFrost2
anchors.fill: fastBlur2
color: "white"
}
FastBlur {
id: fastBlur2
anchors.fill: recControls2
source: ShaderEffectSource {
sourceItem: imgBackground
sourceRect: Qt.rect(
swipeView.width - swipeView.contentItem.contentX + fastBlur2.x,
fastBlur2.y,
fastBlur2.width,
fastBlur2.height)
}
radius: 32
opacity: 0.55
}
Rectangle {
id: recControls2
width: 364
height: 89
color: "#00000000"
anchors.centerIn: parent
Label {
text: qsTr("Second page")
anchors.centerIn: parent
}
}
}
Item {
id: item3
Rectangle {
id: recFrost3
anchors.fill: fastBlur3
color: "white"
}
FastBlur {
id: fastBlur3
anchors.fill: recControls3
source: ShaderEffectSource {
sourceItem: imgBackground
sourceRect: Qt.rect(
swipeView.width * 2 - swipeView.contentItem.contentX + fastBlur2.x,
fastBlur3.y,
fastBlur3.width,
fastBlur3.height)
}
radius: 32
opacity: 0.55
}
Rectangle {
id: recControls3
width: 364
height: 89
color: "#00000000"
anchors.topMargin: 8
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
Label {
text: qsTr("Third page")
anchors.centerIn: parent
}
}
}
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
TabButton {
text: qsTr("First")
}
TabButton {
text: qsTr("Second")
}
TabButton {
text: qsTr("Third")
}
}
}
您可以使用父页面在 SwipeView
中的 x
位置代替 swipeView.width
增量:
sourceRect: Qt.rect(fastBlur2.x - swipeView.contentItem.contentX + item2.x,
fastBlur2.y,
fastBlur2.width,
astBlur2.height)
或者您可以 Item
的 mapToItem()
。
然而,由于 mapToItem
是一个函数,当一个项目相对于另一个项目移动时,使用它的 return 值不会触发绑定更新,我们必须温和地提示 QML 引擎何时重新评估绑定。
sourceRect: {
swipeView.contentItem.contentX; /*here we access contentX in order to
force the reevaluation of the entire expression when contentX changes.*/
return fastBlur3.mapToItem(swipeView, 0, 0, fastBlur3.width, fastBlur3.height);
}