I have a SwipeView with a background image. It has two pages, both pages have a set of controls and text, and I've put an iOS-like blurred rounded rectangle underneath them so that it's easier to read but doesn't completely block out the nice background
I found this snippet at the end of this thread that led me to use a white rectangle combined with a semi translucent FastBlur that sampled the background: 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)
}
}
When I move to the next page in the SwipeView, the background stays static but the blur doesn't, of course, because the sourceRect region didn't move relative to its parent, just that the parent is being moved relative to the background. The blur is still sampling the background from its original position, not the new position as it's moving through the swipeview
So I picked up the fact that I can get the SwipeView.contentItem.contentX (thanks to the answer at QML: Mid-swipe position of item in SwipeView!) But in both of my pages, I have to account differently for the contentX based on what order they're in
I set up an example blur project here to show what I mean. https://github.com/ftab/BlurTest
Specifically, at the 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)
This gets the desired effect of the blur updating while it moves across the background, but only works because the blurred region is on the first page of the swipe view and contentX goes from 0 to 640. If this were on the second page, I'd have to do 640 - contentX + fastBlur.x, and then if I move it around again I have to adjust it again, etc.
Is there a better way to do this, or am I pretty much stuck hand editing the sourceRect whenever I add another page or change the order?
edit: complete QML file with 3 pages for example:
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")
}
}
}
Instead of doing it with swipeView.width
increments, you could use the x
position of your parent page in the SwipeView
:
sourceRect: Qt.rect(fastBlur2.x - swipeView.contentItem.contentX + item2.x,
fastBlur2.y,
fastBlur2.width,
astBlur2.height)
Alternatively you could Item
's mapToItem()
.
However, since mapToItem
is a function, using its return value won't trigger binding updates when one item moves relatively to the other, we'll have to gently hint the QML engine when to re-evaluate the binding.
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);
}