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{
title:lang.other
icon:FluentIcons.Shop
FluPaneItem{
title:"Tour"
onTap:{
navigationView.push("qrc:/example/qml/page/T_Tour.qml")
}
}
FluPaneItem{
title:"Http"
onTap:{

View File

@ -9,6 +9,19 @@ FluScrollablePage{
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{
Layout.fillWidth: true
height: 370
@ -24,23 +37,95 @@ FluScrollablePage{
text:"轮播图支持无限轮播无限滑动用ListView实现的组件"
}
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.leftMargin: 5
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{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluCarousel{
id:carousel
width: 400
height: 300
delegate: Component{
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
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
anchors.fill: flipable
FluAppBar {
id:app_bar_front
anchors {
top: parent.top
left: parent.left

View File

@ -2,22 +2,41 @@ 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
@ -30,8 +49,18 @@ Item {
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
Component.onCompleted: {
d.setData(control.model)
}
Connections{
target: control
function onModelChanged(){
d.setData(control.model)
}
}
orientation : ListView.Horizontal
delegate: Item{
id:item_control
width: ListView.view.width
height: ListView.view.height
property int displayIndex: {
@ -41,11 +70,16 @@ Item {
return 0
return index-1
}
Image {
Loader{
property int displayIndex : item_control.displayIndex
property var model: list_view.model.get(index)
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
sourceComponent: {
if(model){
return control.delegate
}
return undefined
}
}
}
onMovementEnded:{
@ -55,15 +89,15 @@ Item {
}else if(currentIndex === list_view.count-1){
currentIndex = 1
}
flagXChanged = false
timer_run.start()
d.flagXChanged = false
timer_run.restart()
}
onMovementStarted: {
flagXChanged = true
d.flagXChanged = true
timer_run.stop()
}
onContentXChanged: {
if(flagXChanged){
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){
@ -75,29 +109,63 @@ Item {
}
}
}
}
Row{
spacing: 10
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 20
}
visible: showIndicator
Repeater{
model: list_view.count
Component{
id:com_indicator
Rectangle{
width: 8
height: 8
radius: 4
visible: {
if(index===0 || index===list_view.count-1)
return false
return true
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{
id:layout_indicator
spacing: control.indicatorSpacing
anchors{
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
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()
}
}