UPDATE: Added code for SwipeView
I'm trying to customize the PageIndicator
to do what I currently have three buttons do namely
- Make it possible to change pages by clicking on the respective item inside the
PageIndicator
(currently I have 3 pages, one button per page withonClicked
set to change theSwipeView
to a predefined index - noPageIndicator
) - Display custom image for each page indicator item (currently I have 3 pages, one button per page with a custom image - no
PageIndicator
)
My SwipeView
has the following structure:
SwipeView {
id: detailsView
Layout.fillWidth: true
Layout.preferredHeight: layoutTopLevel.height * .9
Page {
id: captureViewPage
header: Text {
text: "Capture view"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 20
}
}
Page {
id: helpViewPage
header: Text {
text: "Help view"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 20
}
footer: TabBar {
id: helpViewSubCategories
currentIndex: 0
TabButton {
text: qsTr("Gestures")
}
TabButton {
text: qsTr("General")
}
}
}
Page {
id: settingsViewPage
header: Text {
text: "Settings view"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 20
}
footer: TabBar {
id: settingsViewSubCategories
currentIndex: 0
TabButton {
text: qsTr("Language")
}
TabButton {
text: qsTr("Device")
}
}
}
}
Both the SwipeView
and the PageIndicator
(see below) are part of a ColumnLayout
and are sublings:
ColumnLayout {
id: layoutDetailsAndMenu
spacing: 0
SwipeView { ... }
PageIndicator { ... }
}
First of all I have researched how the delegate
property of the PageIndicator
works. For example the following QML code
PageIndicator {
id: detailsViewIndicator
count: detailsView.count
currentIndex: detailsView.currentIndex
interactive: true
anchors.bottom: detailsView.bottom
anchors.bottomMargin: -40
anchors.horizontalCenter: parent.horizontalCenter
delegate: Rectangle {
implicitWidth: 15
implicitHeight: 15
radius: width
color: "#21be2b"
opacity: index === detailsView.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
Behavior on opacity {
OpacityAnimator {
duration: 100
}
}
}
}
produces the following greenish result:
Make it possible to change pages by clicking on the respective item inside the PageIndicator
For some reason the inactive
doesn't work at all. I will quote the documentation what this property is supposed to do:
interactive : bool
This property holds whether the control is interactive. An interactive page indicator reacts to presses and automatically changes the current index appropriately. The default value is false.
I don't know if this is a bug or I'm missing something but even without the customization via delegate
clicking on a page indicator item does NOT change the current page (the number of these items does equal the number of pages so clicking on an index that doesn't have a page assigned to it is out of question).
So in order to make my first wish come true I added a MouseArea
:
PageIndicator {
// ...
delegate: Rectangle {
MouseArea {
anchors.fill: parent
onClicked: {
if(index !== detailsView.currentIndex) {
detailsView.setCurrentIndex(index);
}
}
}
}
}
As you can see I'm using the onClicked
event handler (or whatever these things are called) and check whether the current index of the PageIndicator
equals the page in my SwipeView
. If that's not the case I use setCurrentIndex(index)
to set my SwipeView
to the selected index.
After I wrote this I was pretty satisfied that it worked as I envisioned it (though the interactive
thing is still bothering me). Next thing was to add the images...
Display custom image for each page indicator item
First let me show you how I'd like things to look (this is actually the final result but more on that - later down the line):
NOTE: I've used the Qt
logo which I don't own. It's for demonstration purposes
From left to right the QRC
URLs are:
The source for this is as follows:
delegate: Image {
source: detailsViewIndicator.indicatorIcons[detailsView.currentIndex]
height: 30
width: 30
opacity: index === detailsView.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
MouseArea {
anchors.fill: parent
onClicked: {
if(index !== detailsView.currentIndex) {
detailsView.setCurrentIndex(index);
source = detailsViewIndicator.indicatorIcons[detailsView.currentIndex];
}
}
}
}
where indicatorIcons
is a variant
property of my PageIndicator
:
property variant indicatorIcons: [
"qrc:/icons/qtlogo.png",
"qrc:/icons/qtlogo1.png",
"qrc:/icons/qtlogo2.png"
]
I've used an array of string
objects for the QRC
URLs since it seems impossible to do
delegate: detailsViewIndicator.indicatorImages[detailsView.currentIndex]
with indicatorImages
being
property list<Image> indicatorImages: [
Image { source: "..." },
Image { source: "..." },
Image { source: "..." }
]
The issues I'm having are with the actual loading of the images and I'm have the feeling that it has something to do with the list
problem I've described above. With the code
delegate: Image {
source: detailsViewIndicator.indicatorIcons[detailsView.currentIndex]
// ...
}
first time I run my application I get:
This is due to the fact that the initially selected index is 0
so an Image
with source: "qrc:/icons/qtlogo.png"
is generated an all page indicator items are populated with it. If I select one of the other two as the initially selected page I will get qrc:/icons/qtlogo1.png
and qrc:/icons/qtlogo2.png
respectively.
Swiping in the SwipeView
(not clicking on the PageIndicator
) leads to
and
This only in one direction (index-wise from left to right). If I go backwards I get the same results but in the opposite order.
Clicking makes things more interesting. In the screenshot below I've clicked on the second page indicator item (with qrc:/icons/qtlogo1.png
as source for the Image
) after the initialization:
Next I clicked on the third page indicator item:
After some more clicking I got:
Obviously this is not how things are supposed to work. I'd like to have the final result all the time from start to end and no matter which page has been swiped away or page indicator item clicked.
Has anyone done anything like this? Is this even possible?