From 8377fb52271a48cc8fd71d6ddf207f5756621c77 Mon Sep 17 00:00:00 2001 From: Polaris-Night <158275221@qq.com> Date: Wed, 12 Mar 2025 23:38:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20FluCarousel=E6=94=AF=E6=8C=81=E7=BA=B5?= =?UTF-8?q?=E5=90=91=E8=BD=AE=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/example_en_US.ts | 5 + example/example_zh_CN.ts | 9 +- example/qml/page/T_Carousel.qml | 85 ++++++++- .../imports/FluentUI/Controls/FluCarousel.qml | 163 +++++++++++++----- src/Qt5/imports/FluentUI/plugins.qmltypes | 28 +-- .../imports/FluentUI/Controls/FluCarousel.qml | 163 +++++++++++++----- 6 files changed, 355 insertions(+), 98 deletions(-) diff --git a/example/example_en_US.ts b/example/example_en_US.ts index cd15eb41..390f78c6 100644 --- a/example/example_en_US.ts +++ b/example/example_en_US.ts @@ -1123,6 +1123,11 @@ Updated content: Carousel map, support infinite carousel, infinite swipe, and components implemented with ListView + + + Auto play + + T_CheckBox diff --git a/example/example_zh_CN.ts b/example/example_zh_CN.ts index 276388d8..6796d1c0 100644 --- a/example/example_zh_CN.ts +++ b/example/example_zh_CN.ts @@ -1142,12 +1142,17 @@ Updated content: Carousel - 轮播图 + 轮播图 Carousel map, support infinite carousel, infinite swipe, and components implemented with ListView - 轮播图,支持无限轮播,无限滑动,用ListView实现的组件 + 轮播图,支持无限轮播,无限滑动,用ListView实现的组件 + + + + Auto play + 自动轮播 diff --git a/example/qml/page/T_Carousel.qml b/example/qml/page/T_Carousel.qml index 4d65ff2b..095264b5 100644 --- a/example/qml/page/T_Carousel.qml +++ b/example/qml/page/T_Carousel.qml @@ -121,7 +121,6 @@ FluScrollablePage{ } } - CodeExpander{ Layout.fillWidth: true Layout.topMargin: -6 @@ -140,6 +139,90 @@ FluScrollablePage{ 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"}] } +}' + } + + 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"}] + } }' } } diff --git a/src/Qt5/imports/FluentUI/Controls/FluCarousel.qml b/src/Qt5/imports/FluentUI/Controls/FluCarousel.qml index bc26df83..678b7f36 100644 --- a/src/Qt5/imports/FluentUI/Controls/FluCarousel.qml +++ b/src/Qt5/imports/FluentUI/Controls/FluCarousel.qml @@ -4,6 +4,7 @@ import FluentUI 1.0 Item { property bool autoPlay: true + property int orientation: Qt.Horizontal property int loopTime: 2000 property var model property Component delegate @@ -14,7 +15,7 @@ Item { property int indicatorMarginTop: 0 property int indicatorMarginBottom: 20 property int indicatorSpacing: 10 - property alias indicatorAnchors: layout_indicator.anchors + property alias indicatorAnchors: indicator_loader.anchors property Component indicatorDelegate : com_indicator id:control width: 400 @@ -24,13 +25,24 @@ Item { } QtObject{ id:d - property bool flagXChanged: false + property bool isManualMoving: false property bool isAnimEnable: control.autoPlay && list_view.count>3 + onIsAnimEnableChanged: { + if(isAnimEnable){ + timer_run.restart() + }else{ + timer_run.stop() + } + } function setData(data){ - if(!data){ + if(!data || !Array.isArray(data)){ return } content_model.clear() + list_view.resetPos() + if(data.length === 0){ + return + } content_model.append(data[data.length-1]) content_model.append(data) content_model.append(data[0]) @@ -49,7 +61,7 @@ Item { clip: true boundsBehavior: ListView.StopAtBounds model:content_model - maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height) + maximumFlickVelocity: 4 * (control.orientation === Qt.Vertical ? height : width) preferredHighlightBegin: 0 preferredHighlightEnd: 0 highlightMoveDuration: 0 @@ -63,7 +75,7 @@ Item { d.setData(control.model) } } - orientation : ListView.Horizontal + orientation : control.orientation delegate: Item{ id:item_control width: ListView.view.width @@ -88,34 +100,63 @@ Item { } } onMovementEnded:{ - d.flagXChanged = false + d.isManualMoving = false list_view.highlightMoveDuration = 0 - currentIndex = list_view.contentX/list_view.width - if(currentIndex === 0){ - currentIndex = list_view.count-2 - }else if(currentIndex === list_view.count-1){ - currentIndex = 1 + if(control.orientation === Qt.Vertical){ + currentIndex = (list_view.contentY - list_view.originY) / list_view.height + if(currentIndex === 0){ + currentIndex = list_view.count - 2 + }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){ timer_run.restart() } } onMovementStarted: { - d.flagXChanged = true + d.isManualMoving = true timer_run.stop() } onContentXChanged: { - if(d.flagXChanged){ - var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width) - var minX = Math.max(0,(list_view.width*(currentIndex-1))) - if(contentX>=maxX){ - contentX = maxX + if(d.isManualMoving && control.orientation === Qt.Horizontal){ + const range = getPosRange(list_view.width, currentIndex) + if(contentX >= range.max){ + contentX = range.max } - if(contentX<=minX){ - contentX = minX + if(contentX <= range.min){ + 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{ id:com_indicator @@ -140,9 +181,9 @@ Item { } } } - Row{ - id:layout_indicator - spacing: control.indicatorSpacing + + Loader{ + id: indicator_loader anchors{ horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined @@ -155,28 +196,66 @@ Item { rightMargin: control.indicatorMarginBottom topMargin: control.indicatorMarginBottom } - visible: showIndicator - 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 + active: showIndicator + sourceComponent: control.orientation === Qt.Vertical ? column_indicator : row_indicator + } + + Component{ + id: row_indicator + Row{ + 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 + } } } } } + + 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{ id:timer_anim interval: 250 @@ -198,10 +277,10 @@ Item { } } function changedIndex(index){ - d.flagXChanged = true + d.isManualMoving = true timer_run.stop() list_view.currentIndex = index - d.flagXChanged = false + d.isManualMoving = false if(d.isAnimEnable){ timer_run.restart() } diff --git a/src/Qt5/imports/FluentUI/plugins.qmltypes b/src/Qt5/imports/FluentUI/plugins.qmltypes index 3981b4aa..26d694db 100644 --- a/src/Qt5/imports/FluentUI/plugins.qmltypes +++ b/src/Qt5/imports/FluentUI/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // 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 { dependencies: ["QtQuick 2.0"] @@ -2776,7 +2776,7 @@ Module { } Property { name: "layoutMacosButtons" - type: "FluLoader_QMLTYPE_11" + type: "FluLoader_QMLTYPE_14" isReadonly: true isPointer: true } @@ -2898,6 +2898,7 @@ Module { isComposite: true defaultProperty: "data" Property { name: "autoPlay"; type: "bool" } + Property { name: "orientation"; type: "int" } Property { name: "loopTime"; type: "int" } Property { name: "model"; type: "QVariant" } Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } @@ -2955,12 +2956,12 @@ Module { Property { name: "checkedDisableColor"; type: "QColor" } Property { name: "disableColor"; type: "QColor" } Property { name: "size"; type: "double" } + Property { name: "textColor"; type: "QColor" } Property { name: "textRight"; type: "bool" } Property { name: "textSpacing"; type: "double" } Property { name: "animationEnabled"; type: "bool" } Property { name: "clickListener"; type: "QVariant" } Property { name: "indeterminate"; type: "bool" } - Property { name: "textColor"; type: "QColor" } } Component { prototype: "FluRectangle" @@ -3189,6 +3190,8 @@ Module { isComposite: true defaultProperty: "content" Property { name: "headerText"; type: "string" } + Property { name: "headerHeight"; type: "int" } + Property { name: "headerDelegate"; type: "QQmlComponent"; isPointer: true } Property { name: "expand"; type: "bool" } Property { name: "contentHeight"; type: "int" } Property { name: "content"; type: "QObject"; isList: true; isReadonly: true } @@ -3469,15 +3472,15 @@ Module { defaultProperty: "data" Property { name: "logo"; type: "QUrl" } Property { name: "title"; type: "string" } - Property { name: "items"; type: "FluObject_QMLTYPE_176"; isPointer: true } - Property { name: "footerItems"; type: "FluObject_QMLTYPE_176"; isPointer: true } + Property { name: "items"; type: "FluObject_QMLTYPE_182"; isPointer: true } + Property { name: "footerItems"; type: "FluObject_QMLTYPE_182"; isPointer: true } Property { name: "displayMode"; type: "int" } Property { name: "autoSuggestBox"; type: "QQmlComponent"; isPointer: true } Property { name: "actionItem"; type: "QQmlComponent"; isPointer: true } Property { name: "topPadding"; type: "int" } Property { name: "pageMode"; type: "int" } - Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_48"; isPointer: true } - Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_48"; isPointer: true } + Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_47"; isPointer: true } + Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_47"; isPointer: true } Property { name: "navCompactWidth"; type: "int" } Property { name: "navTopMargin"; type: "int" } Property { name: "cellHeight"; type: "int" } @@ -3676,6 +3679,7 @@ Module { exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "content" + Property { name: "textHighlightColor"; type: "QColor" } Property { name: "textNormalColor"; type: "QColor" } Property { name: "textHoverColor"; type: "QColor" } Property { name: "textSpacing"; type: "int" } @@ -3772,11 +3776,11 @@ Module { Property { name: "normalColor"; type: "QColor" } Property { name: "hoverColor"; type: "QColor" } Property { name: "disableColor"; type: "QColor" } + Property { name: "textColor"; type: "QColor" } Property { name: "size"; type: "double" } Property { name: "textRight"; type: "bool" } Property { name: "textSpacing"; type: "double" } Property { name: "clickListener"; type: "QVariant" } - Property { name: "textColor"; type: "QColor" } } Component { prototype: "QQuickItem" @@ -3899,7 +3903,9 @@ Module { exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "content" + Property { name: "autoResetScroll"; type: "bool" } Property { name: "content"; type: "QObject"; isList: true; isReadonly: true } + Method { name: "resetScroll"; type: "QVariant" } Property { name: "launchMode"; type: "int" } Property { name: "animationEnabled"; type: "bool" } Property { name: "url"; type: "string" } @@ -4294,8 +4300,8 @@ Module { Property { name: "dotDisableColor"; type: "QColor" } Property { name: "textSpacing"; type: "double" } Property { name: "textRight"; type: "bool" } - Property { name: "clickListener"; type: "QVariant" } Property { name: "textColor"; type: "QColor" } + Property { name: "clickListener"; type: "QVariant" } } Component { prototype: "QQuickToolTip" @@ -4379,7 +4385,6 @@ Module { Property { name: "fitsAppBarWindows"; type: "bool" } Property { name: "tintOpacity"; type: "QVariant" } Property { name: "blurRadius"; type: "int" } - Property { name: "availableEffects"; type: "QVariant"; isReadonly: true } Property { name: "appBar"; type: "QQuickItem"; isPointer: true } Property { name: "backgroundColor"; type: "QColor" } Property { name: "stayTop"; type: "bool" } @@ -4403,6 +4408,7 @@ Module { Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true } Property { name: "effect"; type: "string" } Property { name: "effective"; type: "bool"; isReadonly: true } + Property { name: "availableEffects"; type: "QStringList"; isReadonly: true } Signal { name: "initArgument" Parameter { name: "argument"; type: "QVariant" } @@ -4485,7 +4491,6 @@ Module { Property { name: "fitsAppBarWindows"; type: "bool" } Property { name: "tintOpacity"; type: "QVariant" } Property { name: "blurRadius"; type: "int" } - Property { name: "availableEffects"; type: "QVariant"; isReadonly: true } Property { name: "appBar"; type: "QQuickItem"; isPointer: true } Property { name: "backgroundColor"; type: "QColor" } Property { name: "stayTop"; type: "bool" } @@ -4509,6 +4514,7 @@ Module { Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true } Property { name: "effect"; type: "string" } Property { name: "effective"; type: "bool"; isReadonly: true } + Property { name: "availableEffects"; type: "QStringList"; isReadonly: true } Signal { name: "initArgument" Parameter { name: "argument"; type: "QVariant" } diff --git a/src/Qt6/imports/FluentUI/Controls/FluCarousel.qml b/src/Qt6/imports/FluentUI/Controls/FluCarousel.qml index cb364bb8..65b42470 100644 --- a/src/Qt6/imports/FluentUI/Controls/FluCarousel.qml +++ b/src/Qt6/imports/FluentUI/Controls/FluCarousel.qml @@ -4,6 +4,7 @@ import FluentUI Item { property bool autoPlay: true + property int orientation: Qt.Horizontal property int loopTime: 2000 property var model property Component delegate @@ -14,7 +15,7 @@ Item { property int indicatorMarginTop: 0 property int indicatorMarginBottom: 20 property int indicatorSpacing: 10 - property alias indicatorAnchors: layout_indicator.anchors + property alias indicatorAnchors: indicator_loader.anchors property Component indicatorDelegate : com_indicator id:control width: 400 @@ -24,13 +25,24 @@ Item { } QtObject{ id:d - property bool flagXChanged: false + property bool isManualMoving: false property bool isAnimEnable: control.autoPlay && list_view.count>3 + onIsAnimEnableChanged: { + if(isAnimEnable){ + timer_run.restart() + }else{ + timer_run.stop() + } + } function setData(data){ - if(!data){ + if(!data || !Array.isArray(data)){ return } content_model.clear() + list_view.resetPos() + if(data.length === 0){ + return + } content_model.append(data[data.length-1]) content_model.append(data) content_model.append(data[0]) @@ -49,7 +61,7 @@ Item { clip: true boundsBehavior: ListView.StopAtBounds model:content_model - maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height) + maximumFlickVelocity: 4 * (control.orientation === Qt.Vertical ? height : width) preferredHighlightBegin: 0 preferredHighlightEnd: 0 highlightMoveDuration: 0 @@ -63,7 +75,7 @@ Item { d.setData(control.model) } } - orientation : ListView.Horizontal + orientation : control.orientation delegate: Item{ id:item_control width: ListView.view.width @@ -88,34 +100,63 @@ Item { } } onMovementEnded:{ - d.flagXChanged = false + d.isManualMoving = false list_view.highlightMoveDuration = 0 - currentIndex = list_view.contentX/list_view.width - if(currentIndex === 0){ - currentIndex = list_view.count-2 - }else if(currentIndex === list_view.count-1){ - currentIndex = 1 + if(control.orientation === Qt.Vertical){ + currentIndex = (list_view.contentY - list_view.originY) / list_view.height + if(currentIndex === 0){ + currentIndex = list_view.count - 2 + }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){ timer_run.restart() } } onMovementStarted: { - d.flagXChanged = true + d.isManualMoving = true timer_run.stop() } onContentXChanged: { - if(d.flagXChanged){ - var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width) - var minX = Math.max(0,(list_view.width*(currentIndex-1))) - if(contentX>=maxX){ - contentX = maxX + if(d.isManualMoving && control.orientation === Qt.Horizontal){ + const range = getPosRange(list_view.width, currentIndex) + if(contentX >= range.max){ + contentX = range.max } - if(contentX<=minX){ - contentX = minX + if(contentX <= range.min){ + 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{ id:com_indicator @@ -140,9 +181,9 @@ Item { } } } - Row{ - id:layout_indicator - spacing: control.indicatorSpacing + + Loader{ + id: indicator_loader anchors{ horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined @@ -155,28 +196,66 @@ Item { rightMargin: control.indicatorMarginBottom topMargin: control.indicatorMarginBottom } - visible: showIndicator - 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 + active: showIndicator + sourceComponent: control.orientation === Qt.Vertical ? column_indicator : row_indicator + } + + Component{ + id: row_indicator + Row{ + 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 + } } } } } + + 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{ id:timer_anim interval: 250 @@ -198,10 +277,10 @@ Item { } } function changedIndex(index){ - d.flagXChanged = true + d.isManualMoving = true timer_run.stop() list_view.currentIndex = index - d.flagXChanged = false + d.isManualMoving = false if(d.isAnimEnable){ timer_run.restart() }