这篇承接上篇,这回来谈谈ListView的使用,首先的是,先了解ListView的是什么,及其相关的属性代表的作用.
ListView是QML中用于显示垂直或者水平列表的视图组件.他可以显示一系列的项目,并且每个项目的外观和行为由delegate属性定义.ListView通常与数据模型(比ListModel) 搭配使用,以动态生成列表项.它有许多属性可以设置,通过这些不同的属性设置,来达到我们想要达到的列表视图效果;
一.下面是ListView的一些属性说明
1. **model**: 数据模型,可以是一个列表、数组或自定义的模型对象。
2. **delegate**: 用于定义每个列表项的外观和行为。
3. **orientation**: 列表的方向,可以是 `Qt.Vertical` 或 `Qt.Horizontal`。
4. **currentIndex**: 当前选中的项的索引。
5. **currentItem**: 当前选中的项。
6. **highlight**: 用于定义高亮项的外观。
7. **highlightMoveDuration**: 高亮项移动的动画持续时间。
8. **highlightResizeDuration**: 高亮项大小变化的动画持续时间。
9. **highlightFollowsCurrentItem**: 是否让高亮项跟随当前选中的项。
10. **spacing**: 列表项之间的间距。
11. **cacheBuffer**: 用于缓存的像素数。
12. **clip**: 是否裁剪超出边界的内容。
13. **interactive**: 是否允许用户交互。
14. **snapMode**: snapMode属性用于控制 `ListView` 在滚动时是否对齐到项的边界。它可以帮助用户更容易地浏览和选择列表项。`snapMode` 属性有以下几种值:
(1). **ListView.NoSnap**:不对齐到项的边界。滚动是自由的,用户可以停在任意位置。
(2). **ListView.SnapToItem**:对齐到最近的项的边界。当用户停止滚动时,列表会自动调整位置,使最近的项对齐到视图的边界。
(3). **ListView.SnapOneItem**:每次滚动只对齐到一个项的边界。即使用户快速滚动,列表也会逐项对齐。
15. **flickableDirection**: 允许滚动的方向,可以是 `Flickable.AutoFlickDirection`, `Flickable.HorizontalFlick`, `Flickable.VerticalFlick`, 或 `Flickable.HorizontalAndVerticalFlick`.
16. **boundsBehavior**: 控制滚动到边界时的行为,可以是
(1).`Flickable.StopAtBounds`:滚动到边界时停止,不允许超出边界
(2). `Flickable.DragOverBounds`:允许滚动超出边界,但是会有回弹效果
17. **section.property**: 用于分组的属性。
18. **section.criteria**: 分组的标准,可以是 `ViewSection.FullString`, `ViewSection.FirstCharacter`, 或 `ViewSection.FirstLetter`.
19. **section.delegate**: 用于定义分组标题的外观和行为。
上述的属性种类还是比较多的,在实际项目的开发中,只需要使用到一小部分,当需要设置可以来查询对应属性的效果
以下是我个人在项目中的一个示例:
property var numberTexts: ["一", "二", "三", "四", "五", "六", "七", "八", "九"]
ListModel {id: cookStepList}//烹饪步骤
ListView {
id: lvCookingStepList
width: parent.width
height: contentHeight
interactive: false
model:cookStepList
delegate: Column {
width: 552
spacing:12
Text {
id:stepText
width: parent.width
text: qsTr("步骤%1").arg(numberTexts[index])
font.pixelSize: 26
color: "white"
}
Item {
id: imgCookingStepItem
width: parent.width
height: 414
Rectangle{
id:loadingIndicatorCookingStep
width: imgCookingStep.width
height: imgCookingStep.height
radius: 16
color:"#CECECE"
visible: true
Image {
id: imgStepLoading
anchors.centerIn: parent
fillMode: Image.Stretch
source: "you/path/img.png"
}
}
Image {
id: imgCookingStep
width: parent.width
height: parent.height
source: model.fileUrl
clip: true
//保持图片原比例再缩放填充到区域
fillMode: Image.PreserveAspectCrop
asynchronous: true
visible: false //因为显示的是OpacityMask需要false
onStatusChanged: {
if (status == Image.Loading) {
loadingIndicatorCookingStep.visible = true
console.log("Image is loading...")
} else if (status == Image.Ready) {
loadingIndicatorCookingStep.visible = false
console.log("Image loaded successfully.")
} else if (status == Image.Error) {
loadingIndicatorCookingStep.visible = true
console.log("Failed to load image from URL:",
source)
}
}
}
//圆角遮罩Rectangle
Rectangle {
id: maskRecCookingStep
anchors.centerIn: parent
width: imgCookingStep.width
height: imgCookingStep.height
color: "transparent"
Rectangle {
anchors.fill: parent
width: imgCookingStep.paintedWidth
height: imgCookingStep.paintedHeight
color: "black"
radius: 16
}
visible: false //因为显示的是OpacityMask需要false
}
//遮罩后的图案
OpacityMask {
id: maskCookingStep
anchors.fill: imgCookingStep
source: imgCookingStep.source.length===0 ? loadingIndicatorCookingStep : imgCookingStep
maskSource: maskRecCookingStep
}
}
Text {
id: textContent
width: parent.width
text: model.content
font.pixelSize: 26
color: "white"
wrapMode: Text.WordWrap
maximumLineCount: 3
elide: Text.ElideRight
}
Item {
width: parent.width
height: 6
}
}
}
效果的话,各位未来的大佬们可以自己去测试,搭配特定的属性,实现自己需要的效果;还有就是
UI上的一点心得:
1.布局尽可能的简单化,不要使用太复杂的布局属性(避免一些莫名其妙的布局冲突,比如说能用Column,就不用ColumnLayout)
2.复杂的界面就拆分多个简单布局,控制好代码量(方便复用,方便排查问题)