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

@ -331,6 +331,12 @@ FluObject{
FluPaneItemExpander{ FluPaneItemExpander{
title:lang.other title:lang.other
icon:FluentIcons.Shop icon:FluentIcons.Shop
FluPaneItem{
title:"Tour"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Tour.qml")
}
}
FluPaneItem{ FluPaneItem{
title:"Http" title:"Http"
onTap:{ onTap:{

View File

@ -9,6 +9,19 @@ FluScrollablePage{
title:"Carousel" title:"Carousel"
ListModel{
id:data_model
ListElement{
url:"qrc:/example/res/image/banner_1.jpg"
}
ListElement{
url:"qrc:/example/res/image/banner_2.jpg"
}
ListElement{
url:"qrc:/example/res/image/banner_3.jpg"
}
}
FluArea{ FluArea{
Layout.fillWidth: true Layout.fillWidth: true
height: 370 height: 370
@ -24,23 +37,95 @@ FluScrollablePage{
text:"轮播图支持无限轮播无限滑动用ListView实现的组件" text:"轮播图支持无限轮播无限滑动用ListView实现的组件"
} }
FluCarousel{ FluCarousel{
id:carousel radius:[5,5,5,5]
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
Layout.topMargin: 20 Layout.topMargin: 20
Layout.leftMargin: 5 Layout.leftMargin: 5
Component.onCompleted: { Component.onCompleted: {
carousel.setData([{url:"qrc:/example/res/image/banner_1.jpg"},{url:"qrc:/example/res/image/banner_2.jpg"},{url:"qrc:/example/res/image/banner_3.jpg"}]) 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"}]
} }
} }
} }
} }
FluArea{
Layout.fillWidth: true
height: 340
paddings: 10
Layout.topMargin: 10
Column{
spacing: 15
anchors{
verticalCenter: parent.verticalCenter
left:parent.left
}
FluCarousel{
radius:[15,15,15,15]
loopTime:1500
indicatorGravity: Qt.AlignHCenter | Qt.AlignTop
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
font.pixelSize: 15
}
}
}
}
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
}
}
}
}
CodeExpander{ CodeExpander{
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: -1 Layout.topMargin: -1
code:'FluCarousel{ code:'FluCarousel{
id:carousel
width: 400 width: 400
height: 300 height: 300
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
Component.onCompleted: { Component.onCompleted: {
setData([{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"}]
} }
}' }'
} }

View File

@ -0,0 +1,60 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import FluentUI
import "qrc:///example/qml/component"
FluScrollablePage{
title:"Tour"
FluTour{
id:tour
steps:[
{title:"Upload File",description: "Put your files here.",target:()=>btn_upload},
{title:"Save",description: "Save your changes.",target:()=>btn_save},
{title:"Other Actions",description: "Click to see other actions.",target:()=>btn_more}
]
}
FluArea{
Layout.fillWidth: true
height: 130
paddings: 10
Layout.topMargin: 20
FluFilledButton{
anchors{
top: parent.top
topMargin: 14
}
text:"Begin Tour"
onClicked: {
tour.open()
}
}
Row{
spacing: 20
anchors{
top: parent.top
topMargin: 60
}
FluButton{
id:btn_upload
text:"Upload"
}
FluFilledButton{
id:btn_save
text:"Save"
}
FluIconButton{
id:btn_more
iconSource: FluentIcons.More
}
}
}
}

View File

@ -146,6 +146,7 @@ CustomWindow {
visible: flipable.flipAngle !== 180 visible: flipable.flipAngle !== 180
anchors.fill: flipable anchors.fill: flipable
FluAppBar { FluAppBar {
id:app_bar_front
anchors { anchors {
top: parent.top top: parent.top
left: parent.left left: parent.left

View File

@ -2,102 +2,170 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import FluentUI import FluentUI
Item { FluItem {
property bool flagXChanged: true
property int radius : 5
property int loopTime: 2000 property int loopTime: 2000
property var model
property Component delegate
property bool showIndicator: true 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 id:control
width: 400 width: 400
height: 300 height: 300
ListModel{ ListModel{
id:content_model id:content_model
} }
FluRectangle{ QtObject{
anchors.fill: parent id:d
radius: [control.radius,control.radius,control.radius,control.radius] property bool flagXChanged: true
FluShadow{ function setData(data){
radius:control.radius 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 ListView{
anchors.fill: parent id:list_view
snapMode: ListView.SnapOneItem anchors.fill: parent
clip: true snapMode: ListView.SnapOneItem
boundsBehavior: ListView.StopAtBounds clip: true
model:content_model boundsBehavior: ListView.StopAtBounds
maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height) model:content_model
preferredHighlightBegin: 0 maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height)
preferredHighlightEnd: 0 preferredHighlightBegin: 0
highlightMoveDuration: 0 preferredHighlightEnd: 0
orientation : ListView.Horizontal highlightMoveDuration: 0
delegate: Item{ Component.onCompleted: {
width: ListView.view.width d.setData(control.model)
height: ListView.view.height }
property int displayIndex: { Connections{
if(index === 0) target: control
return content_model.count-3 function onModelChanged(){
if(index === content_model.count-1) d.setData(control.model)
return 0
return index-1
}
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
} }
onMovementEnded:{ }
currentIndex = list_view.contentX/list_view.width orientation : ListView.Horizontal
if(currentIndex === 0){ delegate: Item{
currentIndex = list_view.count-2 id:item_control
}else if(currentIndex === list_view.count-1){ width: ListView.view.width
currentIndex = 1 height: ListView.view.height
} property int displayIndex: {
flagXChanged = false if(index === 0)
timer_run.start() return content_model.count-3
if(index === content_model.count-1)
return 0
return index-1
} }
onMovementStarted: { Loader{
flagXChanged = true property int displayIndex : item_control.displayIndex
timer_run.stop() property var model: list_view.model.get(index)
} anchors.fill: parent
onContentXChanged: { sourceComponent: {
if(flagXChanged){ if(model){
var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width) return control.delegate
var minY = Math.max(0,(list_view.width*(currentIndex-1)))
if(contentX>=maxX){
contentX = maxX
}
if(contentX<=minY){
contentX = minY
} }
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{ Row{
spacing: 10 id:layout_indicator
spacing: control.indicatorSpacing
anchors{ anchors{
horizontalCenter: parent.horizontalCenter horizontalCenter:(indicatorGravity & Qt.AlignHCenter) ? parent.horizontalCenter : undefined
bottom: parent.bottom verticalCenter: (indicatorGravity & Qt.AlignVCenter) ? parent.verticalCenter : undefined
bottomMargin: 20 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 visible: showIndicator
Repeater{ Repeater{
id:repeater_indicator
model: list_view.count model: list_view.count
Rectangle{ Loader{
width: 8 property int displayIndex: {
height: 8 if(index === 0)
radius: 4 return list_view.count-3
visible: { if(index === list_view.count-1)
if(index===0 || index===list_view.count-1) return 0
return false return index-1
return true }
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() timer_anim.start()
} }
} }
function setData(data){
content_model.clear() function changedIndex(index){
content_model.append(data[data.length-1]) d.flagXChanged = true
content_model.append(data) timer_run.stop()
content_model.append(data[0]) list_view.currentIndex = index
list_view.currentIndex = 1 d.flagXChanged = false
timer_run.restart() timer_run.restart()
} }
} }

View File

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