feat: FluCarousel支持纵向轮播

This commit is contained in:
Polaris-Night 2025-03-12 23:38:26 +08:00
parent 9ac58a8ca7
commit 8377fb5227
6 changed files with 355 additions and 98 deletions

View File

@ -1123,6 +1123,11 @@ Updated content:
<source>Carousel map, support infinite carousel, infinite swipe, and components implemented with ListView</source> <source>Carousel map, support infinite carousel, infinite swipe, and components implemented with ListView</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="qml/page/T_Carousel.qml" line="203"/>
<source>Auto play</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>T_CheckBox</name> <name>T_CheckBox</name>

View File

@ -1142,12 +1142,17 @@ Updated content:
<message> <message>
<location filename="qml/page/T_Carousel.qml" line="10"/> <location filename="qml/page/T_Carousel.qml" line="10"/>
<source>Carousel</source> <source>Carousel</source>
<translation type="unfinished"></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Carousel.qml" line="36"/> <location filename="qml/page/T_Carousel.qml" line="36"/>
<source>Carousel map, support infinite carousel, infinite swipe, and components implemented with ListView</source> <source>Carousel map, support infinite carousel, infinite swipe, and components implemented with ListView</source>
<translation type="unfinished">ListView实现的组件</translation> <translation>ListView实现的组件</translation>
</message>
<message>
<location filename="qml/page/T_Carousel.qml" line="203"/>
<source>Auto play</source>
<translation></translation>
</message> </message>
</context> </context>
<context> <context>

View File

@ -121,7 +121,6 @@ FluScrollablePage{
} }
} }
CodeExpander{ CodeExpander{
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: -6 Layout.topMargin: -6
@ -140,6 +139,90 @@ FluScrollablePage{
Component.onCompleted: { Component.onCompleted: {
carousel.model = [{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}] carousel.model = [{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}]
} }
}'
}
FluFrame{
Layout.fillWidth: true
Layout.preferredHeight: 300 + topPadding + bottomPadding
padding: 10
Layout.topMargin: 10
RowLayout{
anchors.fill: parent
Item{
Layout.preferredWidth: 400
Layout.fillHeight: true
FluShadow{
radius: 8
}
FluCarousel{
anchors.fill: parent
orientation: Qt.Vertical
autoPlay: auto_play_switch.checked
loopTime:1500
indicatorGravity: Qt.AlignVCenter | Qt.AlignRight
indicatorMarginTop:15
delegate: Component{
Item{
anchors.fill: parent
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
Rectangle{
height: 40
width: parent.width
anchors.bottom: parent.bottom
color: "#33000000"
FluText{
anchors.fill: parent
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
text:model.title
color: FluColors.Grey10
}
}
}
}
Layout.topMargin: 20
Layout.leftMargin: 5
Component.onCompleted: {
var arr = []
arr.push({url:"qrc:/example/res/image/banner_1.jpg",title:"共同应对全球性问题"})
arr.push({url:"qrc:/example/res/image/banner_2.jpg",title:"三小只全程没互动"})
arr.push({url:"qrc:/example/res/image/banner_3.jpg",title:"有效投资扩大 激发增长动能"})
model = arr
}
}
}
FluToggleSwitch{
id: auto_play_switch
Layout.alignment: Qt.AlignRight
text: qsTr("Auto play")
}
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -6
code:'FluCarousel{
id:carousel
width: 400
height: 300
orientation: Qt.Vertical
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
Component.onCompleted: {
carousel.model = [{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}]
}
}' }'
} }
} }

View File

@ -4,6 +4,7 @@ import FluentUI 1.0
Item { Item {
property bool autoPlay: true property bool autoPlay: true
property int orientation: Qt.Horizontal
property int loopTime: 2000 property int loopTime: 2000
property var model property var model
property Component delegate property Component delegate
@ -14,7 +15,7 @@ Item {
property int indicatorMarginTop: 0 property int indicatorMarginTop: 0
property int indicatorMarginBottom: 20 property int indicatorMarginBottom: 20
property int indicatorSpacing: 10 property int indicatorSpacing: 10
property alias indicatorAnchors: layout_indicator.anchors property alias indicatorAnchors: indicator_loader.anchors
property Component indicatorDelegate : com_indicator property Component indicatorDelegate : com_indicator
id:control id:control
width: 400 width: 400
@ -24,13 +25,24 @@ Item {
} }
QtObject{ QtObject{
id:d id:d
property bool flagXChanged: false property bool isManualMoving: false
property bool isAnimEnable: control.autoPlay && list_view.count>3 property bool isAnimEnable: control.autoPlay && list_view.count>3
onIsAnimEnableChanged: {
if(isAnimEnable){
timer_run.restart()
}else{
timer_run.stop()
}
}
function setData(data){ function setData(data){
if(!data){ if(!data || !Array.isArray(data)){
return return
} }
content_model.clear() content_model.clear()
list_view.resetPos()
if(data.length === 0){
return
}
content_model.append(data[data.length-1]) content_model.append(data[data.length-1])
content_model.append(data) content_model.append(data)
content_model.append(data[0]) content_model.append(data[0])
@ -49,7 +61,7 @@ Item {
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
model:content_model model:content_model
maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height) maximumFlickVelocity: 4 * (control.orientation === Qt.Vertical ? height : width)
preferredHighlightBegin: 0 preferredHighlightBegin: 0
preferredHighlightEnd: 0 preferredHighlightEnd: 0
highlightMoveDuration: 0 highlightMoveDuration: 0
@ -63,7 +75,7 @@ Item {
d.setData(control.model) d.setData(control.model)
} }
} }
orientation : ListView.Horizontal orientation : control.orientation
delegate: Item{ delegate: Item{
id:item_control id:item_control
width: ListView.view.width width: ListView.view.width
@ -88,34 +100,63 @@ Item {
} }
} }
onMovementEnded:{ onMovementEnded:{
d.flagXChanged = false d.isManualMoving = false
list_view.highlightMoveDuration = 0 list_view.highlightMoveDuration = 0
currentIndex = list_view.contentX/list_view.width if(control.orientation === Qt.Vertical){
if(currentIndex === 0){ currentIndex = (list_view.contentY - list_view.originY) / list_view.height
currentIndex = list_view.count-2 if(currentIndex === 0){
}else if(currentIndex === list_view.count-1){ currentIndex = list_view.count - 2
currentIndex = 1 }else if(currentIndex === list_view.count - 1) {
currentIndex = 1
}
} else {
currentIndex = (list_view.contentX - list_view.originX) / list_view.width
if(currentIndex === 0){
currentIndex = list_view.count - 2
}else if(currentIndex === list_view.count - 1){
currentIndex = 1
}
} }
if(d.isAnimEnable){ if(d.isAnimEnable){
timer_run.restart() timer_run.restart()
} }
} }
onMovementStarted: { onMovementStarted: {
d.flagXChanged = true d.isManualMoving = true
timer_run.stop() timer_run.stop()
} }
onContentXChanged: { onContentXChanged: {
if(d.flagXChanged){ if(d.isManualMoving && control.orientation === Qt.Horizontal){
var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width) const range = getPosRange(list_view.width, currentIndex)
var minX = Math.max(0,(list_view.width*(currentIndex-1))) if(contentX >= range.max){
if(contentX>=maxX){ contentX = range.max
contentX = maxX
} }
if(contentX<=minX){ if(contentX <= range.min){
contentX = minX contentX = range.min
} }
} }
} }
onContentYChanged: {
if(d.isManualMoving && control.orientation === Qt.Vertical){
const range = getPosRange(list_view.height, currentIndex)
if(contentY >= range.max){
contentY = range.max
}
if(contentY <= range.min){
contentY = range.min
}
}
}
function resetPos() {
contentX = 0
contentY = 0
}
function getPosRange(size, index) {
return {
"min": Math.max(0, size * (index - 1)),
"max": Math.min(size * (index + 1), list_view.count * size)
}
}
} }
Component{ Component{
id:com_indicator id:com_indicator
@ -140,9 +181,9 @@ Item {
} }
} }
} }
Row{
id:layout_indicator Loader{
spacing: control.indicatorSpacing id: indicator_loader
anchors{ anchors{
horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined
verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined
@ -155,28 +196,66 @@ Item {
rightMargin: control.indicatorMarginBottom rightMargin: control.indicatorMarginBottom
topMargin: control.indicatorMarginBottom topMargin: control.indicatorMarginBottom
} }
visible: showIndicator active: showIndicator
Repeater{ sourceComponent: control.orientation === Qt.Vertical ? column_indicator : row_indicator
id:repeater_indicator }
model: list_view.count
FluLoader{ Component{
property int displayIndex: { id: row_indicator
if(index === 0) Row{
return list_view.count-3 id:layout_indicator
if(index === list_view.count-1) spacing: control.indicatorSpacing
return 0 Repeater{
return index-1 id:repeater_indicator
} model: list_view.count
property int realIndex: index FluLoader{
property bool checked: list_view.currentIndex === index property int displayIndex: {
sourceComponent: { if(index === 0)
if(index===0 || index===list_view.count-1) return list_view.count-3
return undefined if(index === list_view.count-1)
return control.indicatorDelegate return 0
return index-1
}
property int realIndex: index
property bool checked: list_view.currentIndex === index
sourceComponent: {
if(index===0 || index===list_view.count-1)
return undefined
return control.indicatorDelegate
}
} }
} }
} }
} }
Component{
id: column_indicator
Column{
id:layout_indicator
spacing: control.indicatorSpacing
Repeater{
id:repeater_indicator
model: list_view.count
FluLoader{
property int displayIndex: {
if(index === 0)
return list_view.count-3
if(index === list_view.count-1)
return 0
return index-1
}
property int realIndex: index
property bool checked: list_view.currentIndex === index
sourceComponent: {
if(index===0 || index===list_view.count-1)
return undefined
return control.indicatorDelegate
}
}
}
}
}
Timer{ Timer{
id:timer_anim id:timer_anim
interval: 250 interval: 250
@ -198,10 +277,10 @@ Item {
} }
} }
function changedIndex(index){ function changedIndex(index){
d.flagXChanged = true d.isManualMoving = true
timer_run.stop() timer_run.stop()
list_view.currentIndex = index list_view.currentIndex = index
d.flagXChanged = false d.isManualMoving = false
if(d.isAnimEnable){ if(d.isAnimEnable){
timer_run.restart() timer_run.restart()
} }

View File

@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only. // It is used for QML tooling purposes only.
// //
// This file was auto-generated by: // This file was auto-generated by:
// 'qmlplugindump -nonrelocatable -noinstantiate FluentUI 1.0 F:/FluentUI/build/Desktop_Qt_5_15_2_MSVC2019_32bit-Release/src' // 'qmlplugindump -nonrelocatable -noinstantiate FluentUI 1.0 E:/develop/QtCode/opensource/FluentUI/build/Desktop_Qt_5_15_2_MinGW_64_bit-Release/src'
Module { Module {
dependencies: ["QtQuick 2.0"] dependencies: ["QtQuick 2.0"]
@ -2776,7 +2776,7 @@ Module {
} }
Property { Property {
name: "layoutMacosButtons" name: "layoutMacosButtons"
type: "FluLoader_QMLTYPE_11" type: "FluLoader_QMLTYPE_14"
isReadonly: true isReadonly: true
isPointer: true isPointer: true
} }
@ -2898,6 +2898,7 @@ Module {
isComposite: true isComposite: true
defaultProperty: "data" defaultProperty: "data"
Property { name: "autoPlay"; type: "bool" } Property { name: "autoPlay"; type: "bool" }
Property { name: "orientation"; type: "int" }
Property { name: "loopTime"; type: "int" } Property { name: "loopTime"; type: "int" }
Property { name: "model"; type: "QVariant" } Property { name: "model"; type: "QVariant" }
Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } Property { name: "delegate"; type: "QQmlComponent"; isPointer: true }
@ -2955,12 +2956,12 @@ Module {
Property { name: "checkedDisableColor"; type: "QColor" } Property { name: "checkedDisableColor"; type: "QColor" }
Property { name: "disableColor"; type: "QColor" } Property { name: "disableColor"; type: "QColor" }
Property { name: "size"; type: "double" } Property { name: "size"; type: "double" }
Property { name: "textColor"; type: "QColor" }
Property { name: "textRight"; type: "bool" } Property { name: "textRight"; type: "bool" }
Property { name: "textSpacing"; type: "double" } Property { name: "textSpacing"; type: "double" }
Property { name: "animationEnabled"; type: "bool" } Property { name: "animationEnabled"; type: "bool" }
Property { name: "clickListener"; type: "QVariant" } Property { name: "clickListener"; type: "QVariant" }
Property { name: "indeterminate"; type: "bool" } Property { name: "indeterminate"; type: "bool" }
Property { name: "textColor"; type: "QColor" }
} }
Component { Component {
prototype: "FluRectangle" prototype: "FluRectangle"
@ -3189,6 +3190,8 @@ Module {
isComposite: true isComposite: true
defaultProperty: "content" defaultProperty: "content"
Property { name: "headerText"; type: "string" } Property { name: "headerText"; type: "string" }
Property { name: "headerHeight"; type: "int" }
Property { name: "headerDelegate"; type: "QQmlComponent"; isPointer: true }
Property { name: "expand"; type: "bool" } Property { name: "expand"; type: "bool" }
Property { name: "contentHeight"; type: "int" } Property { name: "contentHeight"; type: "int" }
Property { name: "content"; type: "QObject"; isList: true; isReadonly: true } Property { name: "content"; type: "QObject"; isList: true; isReadonly: true }
@ -3469,15 +3472,15 @@ Module {
defaultProperty: "data" defaultProperty: "data"
Property { name: "logo"; type: "QUrl" } Property { name: "logo"; type: "QUrl" }
Property { name: "title"; type: "string" } Property { name: "title"; type: "string" }
Property { name: "items"; type: "FluObject_QMLTYPE_176"; isPointer: true } Property { name: "items"; type: "FluObject_QMLTYPE_182"; isPointer: true }
Property { name: "footerItems"; type: "FluObject_QMLTYPE_176"; isPointer: true } Property { name: "footerItems"; type: "FluObject_QMLTYPE_182"; isPointer: true }
Property { name: "displayMode"; type: "int" } Property { name: "displayMode"; type: "int" }
Property { name: "autoSuggestBox"; type: "QQmlComponent"; isPointer: true } Property { name: "autoSuggestBox"; type: "QQmlComponent"; isPointer: true }
Property { name: "actionItem"; type: "QQmlComponent"; isPointer: true } Property { name: "actionItem"; type: "QQmlComponent"; isPointer: true }
Property { name: "topPadding"; type: "int" } Property { name: "topPadding"; type: "int" }
Property { name: "pageMode"; type: "int" } Property { name: "pageMode"; type: "int" }
Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_48"; isPointer: true } Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_47"; isPointer: true }
Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_48"; isPointer: true } Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_47"; isPointer: true }
Property { name: "navCompactWidth"; type: "int" } Property { name: "navCompactWidth"; type: "int" }
Property { name: "navTopMargin"; type: "int" } Property { name: "navTopMargin"; type: "int" }
Property { name: "cellHeight"; type: "int" } Property { name: "cellHeight"; type: "int" }
@ -3676,6 +3679,7 @@ Module {
exportMetaObjectRevisions: [0] exportMetaObjectRevisions: [0]
isComposite: true isComposite: true
defaultProperty: "content" defaultProperty: "content"
Property { name: "textHighlightColor"; type: "QColor" }
Property { name: "textNormalColor"; type: "QColor" } Property { name: "textNormalColor"; type: "QColor" }
Property { name: "textHoverColor"; type: "QColor" } Property { name: "textHoverColor"; type: "QColor" }
Property { name: "textSpacing"; type: "int" } Property { name: "textSpacing"; type: "int" }
@ -3772,11 +3776,11 @@ Module {
Property { name: "normalColor"; type: "QColor" } Property { name: "normalColor"; type: "QColor" }
Property { name: "hoverColor"; type: "QColor" } Property { name: "hoverColor"; type: "QColor" }
Property { name: "disableColor"; type: "QColor" } Property { name: "disableColor"; type: "QColor" }
Property { name: "textColor"; type: "QColor" }
Property { name: "size"; type: "double" } Property { name: "size"; type: "double" }
Property { name: "textRight"; type: "bool" } Property { name: "textRight"; type: "bool" }
Property { name: "textSpacing"; type: "double" } Property { name: "textSpacing"; type: "double" }
Property { name: "clickListener"; type: "QVariant" } Property { name: "clickListener"; type: "QVariant" }
Property { name: "textColor"; type: "QColor" }
} }
Component { Component {
prototype: "QQuickItem" prototype: "QQuickItem"
@ -3899,7 +3903,9 @@ Module {
exportMetaObjectRevisions: [0] exportMetaObjectRevisions: [0]
isComposite: true isComposite: true
defaultProperty: "content" defaultProperty: "content"
Property { name: "autoResetScroll"; type: "bool" }
Property { name: "content"; type: "QObject"; isList: true; isReadonly: true } Property { name: "content"; type: "QObject"; isList: true; isReadonly: true }
Method { name: "resetScroll"; type: "QVariant" }
Property { name: "launchMode"; type: "int" } Property { name: "launchMode"; type: "int" }
Property { name: "animationEnabled"; type: "bool" } Property { name: "animationEnabled"; type: "bool" }
Property { name: "url"; type: "string" } Property { name: "url"; type: "string" }
@ -4294,8 +4300,8 @@ Module {
Property { name: "dotDisableColor"; type: "QColor" } Property { name: "dotDisableColor"; type: "QColor" }
Property { name: "textSpacing"; type: "double" } Property { name: "textSpacing"; type: "double" }
Property { name: "textRight"; type: "bool" } Property { name: "textRight"; type: "bool" }
Property { name: "clickListener"; type: "QVariant" }
Property { name: "textColor"; type: "QColor" } Property { name: "textColor"; type: "QColor" }
Property { name: "clickListener"; type: "QVariant" }
} }
Component { Component {
prototype: "QQuickToolTip" prototype: "QQuickToolTip"
@ -4379,7 +4385,6 @@ Module {
Property { name: "fitsAppBarWindows"; type: "bool" } Property { name: "fitsAppBarWindows"; type: "bool" }
Property { name: "tintOpacity"; type: "QVariant" } Property { name: "tintOpacity"; type: "QVariant" }
Property { name: "blurRadius"; type: "int" } Property { name: "blurRadius"; type: "int" }
Property { name: "availableEffects"; type: "QVariant"; isReadonly: true }
Property { name: "appBar"; type: "QQuickItem"; isPointer: true } Property { name: "appBar"; type: "QQuickItem"; isPointer: true }
Property { name: "backgroundColor"; type: "QColor" } Property { name: "backgroundColor"; type: "QColor" }
Property { name: "stayTop"; type: "bool" } Property { name: "stayTop"; type: "bool" }
@ -4403,6 +4408,7 @@ Module {
Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true } Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "effect"; type: "string" } Property { name: "effect"; type: "string" }
Property { name: "effective"; type: "bool"; isReadonly: true } Property { name: "effective"; type: "bool"; isReadonly: true }
Property { name: "availableEffects"; type: "QStringList"; isReadonly: true }
Signal { Signal {
name: "initArgument" name: "initArgument"
Parameter { name: "argument"; type: "QVariant" } Parameter { name: "argument"; type: "QVariant" }
@ -4485,7 +4491,6 @@ Module {
Property { name: "fitsAppBarWindows"; type: "bool" } Property { name: "fitsAppBarWindows"; type: "bool" }
Property { name: "tintOpacity"; type: "QVariant" } Property { name: "tintOpacity"; type: "QVariant" }
Property { name: "blurRadius"; type: "int" } Property { name: "blurRadius"; type: "int" }
Property { name: "availableEffects"; type: "QVariant"; isReadonly: true }
Property { name: "appBar"; type: "QQuickItem"; isPointer: true } Property { name: "appBar"; type: "QQuickItem"; isPointer: true }
Property { name: "backgroundColor"; type: "QColor" } Property { name: "backgroundColor"; type: "QColor" }
Property { name: "stayTop"; type: "bool" } Property { name: "stayTop"; type: "bool" }
@ -4509,6 +4514,7 @@ Module {
Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true } Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "effect"; type: "string" } Property { name: "effect"; type: "string" }
Property { name: "effective"; type: "bool"; isReadonly: true } Property { name: "effective"; type: "bool"; isReadonly: true }
Property { name: "availableEffects"; type: "QStringList"; isReadonly: true }
Signal { Signal {
name: "initArgument" name: "initArgument"
Parameter { name: "argument"; type: "QVariant" } Parameter { name: "argument"; type: "QVariant" }

View File

@ -4,6 +4,7 @@ import FluentUI
Item { Item {
property bool autoPlay: true property bool autoPlay: true
property int orientation: Qt.Horizontal
property int loopTime: 2000 property int loopTime: 2000
property var model property var model
property Component delegate property Component delegate
@ -14,7 +15,7 @@ Item {
property int indicatorMarginTop: 0 property int indicatorMarginTop: 0
property int indicatorMarginBottom: 20 property int indicatorMarginBottom: 20
property int indicatorSpacing: 10 property int indicatorSpacing: 10
property alias indicatorAnchors: layout_indicator.anchors property alias indicatorAnchors: indicator_loader.anchors
property Component indicatorDelegate : com_indicator property Component indicatorDelegate : com_indicator
id:control id:control
width: 400 width: 400
@ -24,13 +25,24 @@ Item {
} }
QtObject{ QtObject{
id:d id:d
property bool flagXChanged: false property bool isManualMoving: false
property bool isAnimEnable: control.autoPlay && list_view.count>3 property bool isAnimEnable: control.autoPlay && list_view.count>3
onIsAnimEnableChanged: {
if(isAnimEnable){
timer_run.restart()
}else{
timer_run.stop()
}
}
function setData(data){ function setData(data){
if(!data){ if(!data || !Array.isArray(data)){
return return
} }
content_model.clear() content_model.clear()
list_view.resetPos()
if(data.length === 0){
return
}
content_model.append(data[data.length-1]) content_model.append(data[data.length-1])
content_model.append(data) content_model.append(data)
content_model.append(data[0]) content_model.append(data[0])
@ -49,7 +61,7 @@ Item {
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
model:content_model model:content_model
maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height) maximumFlickVelocity: 4 * (control.orientation === Qt.Vertical ? height : width)
preferredHighlightBegin: 0 preferredHighlightBegin: 0
preferredHighlightEnd: 0 preferredHighlightEnd: 0
highlightMoveDuration: 0 highlightMoveDuration: 0
@ -63,7 +75,7 @@ Item {
d.setData(control.model) d.setData(control.model)
} }
} }
orientation : ListView.Horizontal orientation : control.orientation
delegate: Item{ delegate: Item{
id:item_control id:item_control
width: ListView.view.width width: ListView.view.width
@ -88,34 +100,63 @@ Item {
} }
} }
onMovementEnded:{ onMovementEnded:{
d.flagXChanged = false d.isManualMoving = false
list_view.highlightMoveDuration = 0 list_view.highlightMoveDuration = 0
currentIndex = list_view.contentX/list_view.width if(control.orientation === Qt.Vertical){
if(currentIndex === 0){ currentIndex = (list_view.contentY - list_view.originY) / list_view.height
currentIndex = list_view.count-2 if(currentIndex === 0){
}else if(currentIndex === list_view.count-1){ currentIndex = list_view.count - 2
currentIndex = 1 }else if(currentIndex === list_view.count - 1) {
currentIndex = 1
}
} else {
currentIndex = (list_view.contentX - list_view.originX) / list_view.width
if(currentIndex === 0){
currentIndex = list_view.count - 2
}else if(currentIndex === list_view.count - 1){
currentIndex = 1
}
} }
if(d.isAnimEnable){ if(d.isAnimEnable){
timer_run.restart() timer_run.restart()
} }
} }
onMovementStarted: { onMovementStarted: {
d.flagXChanged = true d.isManualMoving = true
timer_run.stop() timer_run.stop()
} }
onContentXChanged: { onContentXChanged: {
if(d.flagXChanged){ if(d.isManualMoving && control.orientation === Qt.Horizontal){
var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width) const range = getPosRange(list_view.width, currentIndex)
var minX = Math.max(0,(list_view.width*(currentIndex-1))) if(contentX >= range.max){
if(contentX>=maxX){ contentX = range.max
contentX = maxX
} }
if(contentX<=minX){ if(contentX <= range.min){
contentX = minX contentX = range.min
} }
} }
} }
onContentYChanged: {
if(d.isManualMoving && control.orientation === Qt.Vertical){
const range = getPosRange(list_view.height, currentIndex)
if(contentY >= range.max){
contentY = range.max
}
if(contentY <= range.min){
contentY = range.min
}
}
}
function resetPos() {
contentX = 0
contentY = 0
}
function getPosRange(size, index) {
return {
"min": Math.max(0, size * (index - 1)),
"max": Math.min(size * (index + 1), list_view.count * size)
}
}
} }
Component{ Component{
id:com_indicator id:com_indicator
@ -140,9 +181,9 @@ Item {
} }
} }
} }
Row{
id:layout_indicator Loader{
spacing: control.indicatorSpacing id: indicator_loader
anchors{ anchors{
horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined
verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined
@ -155,28 +196,66 @@ Item {
rightMargin: control.indicatorMarginBottom rightMargin: control.indicatorMarginBottom
topMargin: control.indicatorMarginBottom topMargin: control.indicatorMarginBottom
} }
visible: showIndicator active: showIndicator
Repeater{ sourceComponent: control.orientation === Qt.Vertical ? column_indicator : row_indicator
id:repeater_indicator }
model: list_view.count
FluLoader{ Component{
property int displayIndex: { id: row_indicator
if(index === 0) Row{
return list_view.count-3 id:layout_indicator
if(index === list_view.count-1) spacing: control.indicatorSpacing
return 0 Repeater{
return index-1 id:repeater_indicator
} model: list_view.count
property int realIndex: index FluLoader{
property bool checked: list_view.currentIndex === index property int displayIndex: {
sourceComponent: { if(index === 0)
if(index===0 || index===list_view.count-1) return list_view.count-3
return undefined if(index === list_view.count-1)
return control.indicatorDelegate return 0
return index-1
}
property int realIndex: index
property bool checked: list_view.currentIndex === index
sourceComponent: {
if(index===0 || index===list_view.count-1)
return undefined
return control.indicatorDelegate
}
} }
} }
} }
} }
Component{
id: column_indicator
Column{
id:layout_indicator
spacing: control.indicatorSpacing
Repeater{
id:repeater_indicator
model: list_view.count
FluLoader{
property int displayIndex: {
if(index === 0)
return list_view.count-3
if(index === list_view.count-1)
return 0
return index-1
}
property int realIndex: index
property bool checked: list_view.currentIndex === index
sourceComponent: {
if(index===0 || index===list_view.count-1)
return undefined
return control.indicatorDelegate
}
}
}
}
}
Timer{ Timer{
id:timer_anim id:timer_anim
interval: 250 interval: 250
@ -198,10 +277,10 @@ Item {
} }
} }
function changedIndex(index){ function changedIndex(index){
d.flagXChanged = true d.isManualMoving = true
timer_run.stop() timer_run.stop()
list_view.currentIndex = index list_view.currentIndex = index
d.flagXChanged = false d.isManualMoving = false
if(d.isAnimEnable){ if(d.isAnimEnable){
timer_run.restart() timer_run.restart()
} }