Can We have a SwipeView by using PathView? - qt

In QML Swipe View is not bidirectional.So I need a swipe view
A code sample will be very beneficial for me.
I need to keep only 3 items in my view & at a time only item should be visible & on swiping the view in either way left or right element should be on center.

This code solves half problem That is why I posted as answer
import QtQuick 2.0
Item {
property alias model: view.model
property alias delegate: view.delegate
property alias currentIndex: view.currentIndex
property real itemHeight: 60
clip: true
PathView {
id: view
anchors.fill: parent
snapMode: PathView.NoSnap
pathItemCount: height/itemHeight
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
dragMargin: view.width/5
path: Path {
startY: view.width/4; startX:-itemHeight/2 -50
PathLine { y: view.width/4; x: (view.pathItemCount*itemHeight + 3*itemHeight) }
}
}
}
And this is My Item :
Item{
id:widgetMain
width :480
height : 240
property int delegateHeight: widgetMain.height
property int delegateWidth : widgetMain.width
Spinner {
id: spinner
width: parent.width;
height: parent.height;
focus: true
model: ["qrc:/Tile1.qml",
"qrc:/Tile2.qml"
,"qrc:/Tile3.qml"]
itemHeight: 150
delegate: Loader {
width: delegateWidth
height: delegateHeight
source: modelData
}
}
}
Now If I swipe towards any direction, It shows only 1 tile in the view. & When my drag reaches to half way, then the tile removes & shifts to last.
Here I want to display that one tile is swiping & 2nd tile is coming from behind(Just like a Swipe view).
Now can you help me please?

Related

TestCase mouseDrag only clicks item inside Flickable but does not drag

In a QML TestCase, I'm trying to setup automatic scrolling of a ListView that is contained inside a Flickable (to add a custom footer that can be flicked into view, which wouldn't happen with just ListView { footer: Component {} })
However, the mouseDrag only seems to click the correct coordinate, but not drag it to any direction. Here is a simplified version that is as close to the real one as possible:
Implementation.qml
import QtQuick 2.5
FocusScope {
width: 1920
height: 1080
Flickable {
objectName: 'flickableList'
boundsBehavior: Flickable.StopAtBounds
clip: true
width: parent.width
height: 240
contentHeight: 500
ListView {
interactive: false
height: parent.height
width: parent.width
model: ['example1', 'example2', 'example3', 'example4', 'example5']
delegate: Item {
width: 300
height: 100
Text {
text: modelData
}
}
}
}
Item {
id: footer
height: 100
width: parent.width
}
}
TheTest.qml
// The relevant part
var theList = findChild(getView(), 'flickableList')
var startY = 220
var endY = 20
mouseDrag(theList, 100, startY, 100, endY, Qt.LeftButton, Qt.NoModifier, 100)
So, when I'm viewing the UI testrunner, I can see it clearly click on the correct delegate (it has a focus highlight in the actual implementation), ie. the third item "example3", which starts at Y 200 and ends at Y 300). But the drag event never happens. Nothing moves on the screen, and compare(theList.contentY, 200) says it is still at position 0. I would expect it to be at 200, since the mouse is supposed to be mouseDragging from position 220 to 20, ie. scrolling the list down by 200. And 220 is also within the visible height (240).
Just to be sure, I also reversed the Y values, but also no movement:
var theList = findChild(getView(), 'flickableList')
var startY = 20
var endY = 220
mouseDrag(theList, 100, startY, 100, endY, Qt.LeftButton, Qt.NoModifier, 100)
Also, as the 3rd item clearly is clicked on (it gets highlighted), the passed item theList (= the Flickable), should be valid.
Edit:
Oh, and this does scroll the list, but it goes all the way to the bottom of the list (388 px down in the actual implementation, even when the delta is just 30 pixels):
mousePress(theList, startX, startY)
mouseMove(theList, endX, endY)
mouseRelease(theList, endX, endY)
So the question is:
Does mouseDrag only work for specific types of components (ie. does not work on Flickable?), or is there something missing? How can I get it to scroll the list down? Thanks!
Your tag says you're using Qt 5.5 - I would recommend trying Qt 5.14 if possible, as there was a fix that might help:
mouseDrag(): ensure that intermediate moves are done for all drags
[...]
In practice, this means that mouseDrag() never did intermediate moves
(i.e. what happens during a drag in real life) for drags that go from
right to left or upwards.
https://codereview.qt-project.org/c/qt/qtdeclarative/+/281903
If that doesn't help, or upgrading is not an option, I would recommend looking at Qt's own tests (although they are written in C++):
https://code.qt.io/cgit/qt/qtdeclarative.git/tree/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp#n1150
I think mouseDrag only works for mouse area. You could wrap every object with that.
But in the end, you need to use a mouse area inside you delegate and Drag and Drop it.
https://doc.qt.io/qt-5/qml-qtquick-drag.html
import QtQuick 2.5
FocusScope {
width: 1920
height: 1080
Flickable {
objectName: 'flickableList'
boundsBehavior: Flickable.StopAtBounds
clip: true
width: parent.width
height: 240
contentHeight: 500
ListView {
interactive: false
height: parent.height
width: parent.width
model: ['example1', 'example2', 'example3', 'example4', 'example5']
delegate: DelegateList{
textAreaText = modelData
}
}
}
Item {
id: footer
height: 100
width: parent.width
}
}
And the DelegateList.qml
Item {
id: root
property alias textAreaText: textArea.text
width: 300
height: 100
Text {
id: textArea
}
Drag.active: dragArea.drag.active
Drag.hotSpot.x: 10
Drag.hotSpot.y: 10
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
}
}

Qml Combobox not closing when delegate of the listview goes out of scope

I have made a delegate for listview that contains Combobox. If I open the Combobox and scroll the listview, the Combobox popup is moving with the delegate position, that's ok. But when the delegate goes out of the listview area(Ref the sample image attached), Combobox popup continues to moves even out of the listview area.
How to close the Combobox when the corresponding delegate goes out of the listview area.
Thanks in advance...
Code goes here
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Column {
spacing: 0
anchors.fill: parent
Item {
width: parent.width
height: parent.height * 0.4
Image {
anchors.fill: parent
anchors.margins: 10
source: "https://lh4.googleusercontent.com/proxy/cITVCAj9KJ5Hfwd5iuNDhzdB2pSrMQv2rzTl-vvg23Ifhe2qdCisZBG-MzV35y_r2zijC9X4QOpda9eHzr_hA"
}
}
ListView {
width: parent.width
height: parent.height * 0.7
model: 10
spacing: 5
clip: true
delegate: Rectangle {
width: parent.width
height: 50
color: index % 2 == 0 ? "lightsteelblue" : "steelblue"
Row {
spacing: 25
anchors.centerIn: parent
Label {
text: qsTr("%1").arg(index)
anchors.verticalCenter: parent.verticalCenter
}
ComboBox {
anchors.verticalCenter: parent.verticalCenter
model: ["a", "b", "c"]
}
}
}
}
}
}
If there is no particular goal to keep ComboBox popup opened when scrolling, then add the following property to your ListView:
highlightRangeMode: ListView.StrictlyEnforceRange
This will close ComboBox popup when ListView is being scrolled.
P.S.
Also, resolves your issue with the ComboBox list getting out of view area.
UPDATE on issue with header element hiding below other list items:
Accordingly to the description ListView.StrictlyEnforceRange - the highlight never moves outside of the range. The current item changes if a keyboard or mouse action would cause the highlight to move outside of the range. when an item goes out of range the list changes next item and that makes ComboBox closing its popup, but since header item is below the other ListView items itself (see this paragraph https://doc.qt.io/qt-5/qml-qtquick-listview.html#stacking-order-in-listview , delegate is always above a header) it makes impossible displaying default header here at the top of the other items. I'd suggest you implement your own header beyond the list. Sorry, I might not have known Qt so good to find the other solution.

How to scroll list view to the current item?

I have a list view. If i click on a cell, that specific cell need to move to the center with a small scrolling animation. With my code, the clicked cell will comes to the center without any animation.
Is it possible to add animation for that ?
Am putting my code below :
ListView {
id: source_list
width: 1080
height: 480
spacing: 50
model: mediaSongsModel
delegate: mediaSongsDelegate
focus: true
interactive: true
clip: true
highlightMoveDuration: 50
snapMode: ListView.SnapToItem
boundsBehavior:Flickable.StopAtBounds
preferredHighlightBegin: 260/scaleFactor
preferredHighlightEnd: 260/scaleFactor
highlightRangeMode: ListView.StrictlyEnforceRange
}
Component {
id: mediaSongsDelegate
Item {
id: wrapper
width: 1080
height: 200
MouseArea {
anchors.fill: parent
onClicked: {
source_list.currentIndex = index
source_list.positionViewAtIndex(index,ListView.Center)
}
}
}
}
If the current item should always be in the center or within a specific are of the view, then you can use the preferredHighlightBegin and preferredHightlightEnd properties to define that area.
The value of highlightRangeMode controls if and if yes, how strictly this applies. E.g. if the first item is the current item and the value is StriclyEnforeRange then the item will be within the specified area even if that means scrolling further up than a normal "scroll to top" would.
Something like that should work
ListView {
preferredHighlightBegin: height / 2 - 100 // 100 being item height / 2
preferredHighlightEnd: height / 2 + 100 // 100 being item height / 2
highlightRangeMode: ListView.StrictlyEnforceRange
}
I've solved my issue by removing the following line of code:
source_list.positionViewAtIndex(index,ListView.Center);
The animation correctly worked.

Building TabBar in QML - Loader doesn't show all the Rectangles

import QtQuick 2.4
import QtQuick.Window 2.2
Window
{
visible: true
height: 500
width: 500
property VisualItemModel contentToBeShownOnTabClick : visualItemModelDemo
property variant tabLabels : ["Navigation", "Payload", "System Control"]
VisualItemModel
{
id: visualItemModelDemo
Rectangle
{
id: navigationTab
color: "green"
height: 200
width: 200
}
Rectangle
{
id: navigationTab1
color: "darkgreen"
height: 200
width: 200
}
Rectangle
{
id: navigationTab2
color: "lightgreen"
height: 200
width: 200
}
}
MainForm
{
Component
{
id: tabsOnBottomComponent
Repeater
{
model: tabLabels
// The Tabs
Rectangle
{
id: tabsOnBottom
// This anchoring places the tabs on the outer top of the parent rectangle.
anchors.top: parent.bottom
anchors.topMargin: 180
color: "lightsteelblue"
border.color: "steelblue"
border.width: 2
implicitWidth: Math.max ((labelTabsBottom.width + 4), 80)
implicitHeight: 20
radius: 2
// Tabs Text/Label
Text
{
id: labelTabsBottom
anchors.centerIn: parent
color: "white"
rotation: 0
// With reference to mode: tabLabels
text: modelData
font.pointSize: 11
}
MouseArea
{
anchors.fill: parent
onClicked: bottomTabClicked (index);
}
}
}
}
Rectangle
{
// The things which get displayed on clicking of a tab will be shown in this rectangle.
id: areaForTabContents
border.color: "black"
border.width: 10
height: parent.height
width : parent.width
color : "pink"
// These are the tabs displayed in one row - horizontally.
Row
{
id: horizontalTabs
Loader
{
anchors.fill: parent
sourceComponent: tabsOnBottomComponent
}
}
}
anchors.fill: parent
}
}
This gets shown as follows:
whereas I want it to see 3 rectangles there side by side.
Loader is not a transparent type w.r.t. the containing type, Row in this case. I think this is an issue related to creation context and the way Repeater works. From the documentation of the latter:
Items instantiated by the Repeater are inserted, in order, as children of the Repeater's parent. The insertion starts immediately after the Repeater's position in its parent stacking list. This allows a Repeater to be used inside a layout.
The Rectangles are indeed added to the parent which is the Loader, they stack up - Loader does not provide a positioning policy - then they are added to the Row resulting in just one Item (the last one) to be visible.
You can tackle the problem with few different approaches, depending on the properties you want to maintain or not. I would get rid of anchoring in the Component and move it to the containing Row. A too specific anchoring inside a Component could be a pain in the neck when it is instanced and used all over a (not so small) project.
As a first approach you can re-parent the Repeater to the Row, i.e. you can rewrite code as:
Row
{
id: horizontalTabs
Loader
{
sourceComponent: tabsOnBottomComponent
onLoaded: item.parent = horizontalTabs
}
}
However this would result in warnings due to the Component anchoring references not working as expected any more.
If you still want to maintain the anchoring, as defined in the Component, and off-load the creation, you can go for the dynamic way (if the semantics fits in your use case), i.e. you can use createObject. This way you totally avoid the Loader and the related issue. For instance, you can create the Repeater once the Row has completed its creation:
Row
{
id: horizontalTabs
Component.onCompleted: tabsOnBottomComponent.createObject(horizontalTabs)
}
Clearly, the creation code can be move anywhere else, depending on your needs.

Pathview Issue in QML

I'm designing the Spinner control (or You can Scollable list of items). Its working fine as far as the functionality is concerned
The main issue is the i want to create a circular motion feel in scrolling the items. So to give that effect in the scrolling list we decided to have preceding & trailing item size comparatively small than current item
I'm really struggling to get the different size of the items. Can any one suggest me how to proceed with the same.
Below is my code snippet
ContentModel.qml
import QtQuick 1.1
Rectangle {
property alias model: view.model
property alias delegate: view.delegate
property real itemHeight: height/5
clip: true
PathView {
id: view
anchors.fill: parent
//number of items visible on the path at any one time.
pathItemCount: height/itemHeight
// Ensuring the selected componenet to be at the center
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
// select maximum distance from the path that initiate mouse dragging
dragMargin: view.width
//Declare the path of list
path: Path {
startX: view.width/2; startY: -itemHeight/2
PathLine { x: view.width/2; y: view.pathItemCount*itemHeight + itemHeight/.8}
}
}
}
The main.qml snippet
main.qml
.......
ContentModel{
id: ContentModel_spinner
width: ContentModel_scroll.width; height: ContentModel_scroll.height
focus: true
model: 20
delegate: Text { font.pixelSize: index === ContentModel_spinner.currentIndex ? sec_spinner.height/4 : ContentModel_spinner.height/4.5; text: formatindex(index); height: ContentModel_scroll.height }
}
Check the tutorial here. They have given examples with different shapes of path views.

Resources