This commit is contained in:
zhuzichu
2023-08-07 18:18:04 +08:00
parent 9bd98c68e4
commit e4fb9989d0
7 changed files with 420 additions and 83 deletions

View File

@ -2,102 +2,170 @@ import QtQuick
import QtQuick.Controls
import FluentUI
Item {
property bool flagXChanged: true
property int radius : 5
FluItem {
property int loopTime: 2000
property var model
property Component delegate
property bool showIndicator: true
property int indicatorGravity : Qt.AlignBottom | Qt.AlignHCenter
property int indicatorMarginLeft: 0
property int indicatorMarginRight: 0
property int indicatorMarginTop: 0
property int indicatorMarginBottom: 20
property int indicatorSpacing: 10
property alias indicatorAnchors: layout_indicator.anchors
property Component indicatorDelegate : com_indicator
id:control
width: 400
height: 300
ListModel{
id:content_model
}
FluRectangle{
anchors.fill: parent
radius: [control.radius,control.radius,control.radius,control.radius]
FluShadow{
radius:control.radius
QtObject{
id:d
property bool flagXChanged: true
function setData(data){
if(!data){
return
}
content_model.clear()
content_model.append(data[data.length-1])
content_model.append(data)
content_model.append(data[0])
list_view.highlightMoveDuration = 0
list_view.currentIndex = 1
list_view.highlightMoveDuration = 250
timer_run.restart()
}
ListView{
id:list_view
anchors.fill: parent
snapMode: ListView.SnapOneItem
clip: true
boundsBehavior: ListView.StopAtBounds
model:content_model
maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height)
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
orientation : ListView.Horizontal
delegate: Item{
width: ListView.view.width
height: ListView.view.height
property int displayIndex: {
if(index === 0)
return content_model.count-3
if(index === content_model.count-1)
return 0
return index-1
}
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
ListView{
id:list_view
anchors.fill: parent
snapMode: ListView.SnapOneItem
clip: true
boundsBehavior: ListView.StopAtBounds
model:content_model
maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height)
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
Component.onCompleted: {
d.setData(control.model)
}
Connections{
target: control
function onModelChanged(){
d.setData(control.model)
}
onMovementEnded:{
currentIndex = list_view.contentX/list_view.width
if(currentIndex === 0){
currentIndex = list_view.count-2
}else if(currentIndex === list_view.count-1){
currentIndex = 1
}
flagXChanged = false
timer_run.start()
}
orientation : ListView.Horizontal
delegate: Item{
id:item_control
width: ListView.view.width
height: ListView.view.height
property int displayIndex: {
if(index === 0)
return content_model.count-3
if(index === content_model.count-1)
return 0
return index-1
}
onMovementStarted: {
flagXChanged = true
timer_run.stop()
}
onContentXChanged: {
if(flagXChanged){
var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width)
var minY = Math.max(0,(list_view.width*(currentIndex-1)))
if(contentX>=maxX){
contentX = maxX
}
if(contentX<=minY){
contentX = minY
Loader{
property int displayIndex : item_control.displayIndex
property var model: list_view.model.get(index)
anchors.fill: parent
sourceComponent: {
if(model){
return control.delegate
}
return undefined
}
}
}
onMovementEnded:{
currentIndex = list_view.contentX/list_view.width
if(currentIndex === 0){
currentIndex = list_view.count-2
}else if(currentIndex === list_view.count-1){
currentIndex = 1
}
d.flagXChanged = false
timer_run.restart()
}
onMovementStarted: {
d.flagXChanged = true
timer_run.stop()
}
onContentXChanged: {
if(d.flagXChanged){
var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width)
var minY = Math.max(0,(list_view.width*(currentIndex-1)))
if(contentX>=maxX){
contentX = maxX
}
if(contentX<=minY){
contentX = minY
}
}
}
}
Component{
id:com_indicator
Rectangle{
width: 8
height: 8
radius: 4
FluShadow{
radius: 4
}
scale: checked ? 1.2 : 1
color: checked ? FluTheme.primaryColor.dark : Qt.rgba(1,1,1,0.7)
border.width: mouse_item.containsMouse ? 1 : 0
border.color: FluTheme.primaryColor.dark
MouseArea{
id:mouse_item
hoverEnabled: true
anchors.fill: parent
onClicked: {
changedIndex(realIndex)
}
}
}
}
Row{
spacing: 10
id:layout_indicator
spacing: control.indicatorSpacing
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 20
horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined
verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined
bottom: (indicatorGravity & Qt.AlignBottom) ? parent.bottom : undefined
top: (indicatorGravity & Qt.AlignTop) ? parent.top : undefined
left: (indicatorGravity & Qt.AlignLeft) ? parent.left : undefined
right: (indicatorGravity & Qt.AlignRight) ? parent.right : undefined
bottomMargin: control.indicatorMarginBottom
leftMargin: control.indicatorMarginBottom
rightMargin: control.indicatorMarginBottom
topMargin: control.indicatorMarginBottom
}
visible: showIndicator
Repeater{
id:repeater_indicator
model: list_view.count
Rectangle{
width: 8
height: 8
radius: 4
visible: {
if(index===0 || index===list_view.count-1)
return false
return true
Loader{
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
}
border.width: 1
border.color: FluColors.Grey100
color: list_view.currentIndex === index ? FluTheme.primaryColor.dark : Qt.rgba(1,1,1,0.5)
}
}
}
@ -121,12 +189,13 @@ Item {
timer_anim.start()
}
}
function setData(data){
content_model.clear()
content_model.append(data[data.length-1])
content_model.append(data)
content_model.append(data[0])
list_view.currentIndex = 1
function changedIndex(index){
d.flagXChanged = true
timer_run.stop()
list_view.currentIndex = index
d.flagXChanged = false
timer_run.restart()
}
}

View File

@ -18,7 +18,7 @@ Item {
property int pageMode: FluNavigationViewType.Stack
signal logoClicked
id:control
QtObject{
Item{
id:d
property bool animDisabled:false
property var stackItems: []
@ -66,6 +66,11 @@ Item {
}
return data
}
function refreshWindow(){
console.debug(Window.window.width)
Window.window.width = Window.window.width-1
Window.window.width = Window.window.width+1
}
}
Component.onCompleted: {
d.displayMode = Qt.binding(function(){
@ -709,6 +714,11 @@ Item {
NumberAnimation{
duration: 167
easing.type: Easing.OutCubic
onRunningChanged: {
if(!running){
d.refreshWindow()
}
}
}
}
Behavior on x {
@ -716,6 +726,11 @@ Item {
NumberAnimation{
duration: 167
easing.type: Easing.OutCubic
onRunningChanged: {
if(!running){
d.refreshWindow()
}
}
}
}
visible: {

View File

@ -0,0 +1,101 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Window
import FluentUI
Popup{
property var steps : []
id:control
padding: 0
anchors.centerIn: Overlay.overlay
width: d.window?.width
height: d.window?.height
background: Item{}
contentItem: Item{}
property int index: 0
property var step : steps[index]
property var target : step.target()
onVisibleChanged: {
if(visible){
index = 0
}
}
Connections{
target: d.window
function onWidthChanged(){
canvas.requestPaint()
}
function onHeightChanged(){
canvas.requestPaint()
}
}
onIndexChanged: {
canvas.requestPaint()
}
Item{
id:d
property var window: Window.window
property var pos:Qt.point(0,0)
}
Canvas{
id:canvas
anchors.fill: parent
onPaint: {
d.pos = target.mapToItem(control,0,0)
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvasSize.width, canvasSize.height);
ctx.save()
ctx.fillStyle = "#66000000"
ctx.fillRect(0, 0, canvasSize.width, canvasSize.height)
ctx.globalCompositeOperation = 'destination-out'
ctx.fillStyle = 'black'
console.debug(d.pos.x)
ctx.fillRect(d.pos.x, d.pos.y, target.width, target.height)
ctx.restore()
}
}
FluRectangle{
radius: [5,5,5,5]
width: 500
height: 120
x: Math.min(Math.max(0,d.pos.x+target.width/2-width/2),d.window?.width-width)
y:d.pos.y+target.height+1
FluFilledButton{
property bool isEnd: control.index === steps.length-1
anchors{
right: parent.right
bottom: parent.bottom
rightMargin: 10
bottomMargin: 10
}
text: isEnd ? "结束导览" :"下一步"
onClicked: {
if(isEnd){
control.close()
}else{
control.index = control.index + 1
}
}
}
}
function refresh(){
canvas.requestPaint()
}
}