在 QML 中滚动两个或多个列表视图
Scroll two or more List views in QML
我需要使用 单个滚动条 同时滚动两个或多个列表视图。最初,我在 Flickable
中使用了 Column
但滚动没有按预期发生。后来,我使用了 ListView
甚至没有正确滚动。
那么如何使用滚动条滚动 listview/layout 内容项?我应该使用 ScrollView
或 Flickable
还是其他什么?
标准滚动条只会挂钩到单个可滚动项目。但是,制作自定义滚动条并将多个视图挂接到它是微不足道的:
Row {
Flickable {
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
contentY: (contentHeight - height) * scroller.position
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Flickable {
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
contentY: (contentHeight - height) * scroller.position
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Rectangle {
id: scroller
width: 50
height: 50
color: "grey"
property real position: y / (main.height - 50)
MouseArea {
anchors.fill: parent
drag.target: parent
drag.minimumY: 0
drag.maximumY: main.height - 50
drag.axis: Drag.YAxis
}
}
}
请注意,即使视图具有不同的内容高度,它也会充分工作,相对于滚动条位置滚动每个视图:
意识到问题提得不太好,以防万一有人想同时滚动多个视图,我还是会分享另一种类似于滚轮的有趣方法,它可以无限期地滚动每个方向,而不是像滚动条那样有一个有限的范围。该解决方案将同步滚动两个视图,直到它们达到其范围的范围。与 GrecKo 的回答不同,当视图大小不同时,这永远不会给您留下 "empty view":
Row {
Flickable {
id: f1
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
Connections {
target: jogger
onScroll: f1.contentY = Math.max(0, Math.min(f1.contentHeight - f1.height, f1.contentY + p))
}
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Flickable {
id: f2
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
Connections {
target: jogger
onScroll: f2.contentY = Math.max(0, Math.min(f2.contentHeight - f2.height, f2.contentY + p))
}
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
MouseArea {
id: jogger
width: 50
height: main.height
drag.target: knob
drag.minimumY: 0
drag.maximumY: main.height - 50
drag.axis: Drag.YAxis
signal scroll(real p)
property real dy: 0
onPressed: dy = mouseY
onPositionChanged: {
scroll(dy - mouseY)
dy = mouseY
}
onScroll: console.log(p)
Rectangle {
anchors.fill: parent
color: "lightgrey"
}
Rectangle {
id: knob
visible: parent.pressed
width: 50
height: 50
color: "grey"
y: Math.max(0, Math.min(parent.mouseY - 25, parent.height - height))
}
}
}
"jog" 方法的另一个优点是它不是相对的而是绝对的。这意味着如果你的视图很大,如果你使用滚动条,即使是单个像素也可能导致内容发生很大的变化,而在绝对模式下工作的慢跑将始终滚动相同数量的像素,而不管内容大小,这是在需要精度的地方很方便。
您可以将 Flickable
与 Columns
一起使用。
我不知道你的 Columns
是如何水平放置的,但如果它们在 Row
内,那就很简单了:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Multi Column")
Flickable {
anchors.fill: parent
contentWidth: row.implicitWidth
contentHeight: row.implicitHeight
Row {
id: row
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
ScrollBar.vertical: ScrollBar { }
}
}
即使他们不在 Row
中,您也可以:
contentHeight: Math.max(column1.height, column2.height, ...)
演示:
我需要使用 单个滚动条 同时滚动两个或多个列表视图。最初,我在 Flickable
中使用了 Column
但滚动没有按预期发生。后来,我使用了 ListView
甚至没有正确滚动。
那么如何使用滚动条滚动 listview/layout 内容项?我应该使用 ScrollView
或 Flickable
还是其他什么?
标准滚动条只会挂钩到单个可滚动项目。但是,制作自定义滚动条并将多个视图挂接到它是微不足道的:
Row {
Flickable {
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
contentY: (contentHeight - height) * scroller.position
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Flickable {
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
contentY: (contentHeight - height) * scroller.position
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Rectangle {
id: scroller
width: 50
height: 50
color: "grey"
property real position: y / (main.height - 50)
MouseArea {
anchors.fill: parent
drag.target: parent
drag.minimumY: 0
drag.maximumY: main.height - 50
drag.axis: Drag.YAxis
}
}
}
请注意,即使视图具有不同的内容高度,它也会充分工作,相对于滚动条位置滚动每个视图:
意识到问题提得不太好,以防万一有人想同时滚动多个视图,我还是会分享另一种类似于滚轮的有趣方法,它可以无限期地滚动每个方向,而不是像滚动条那样有一个有限的范围。该解决方案将同步滚动两个视图,直到它们达到其范围的范围。与 GrecKo 的回答不同,当视图大小不同时,这永远不会给您留下 "empty view":
Row {
Flickable {
id: f1
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
Connections {
target: jogger
onScroll: f1.contentY = Math.max(0, Math.min(f1.contentHeight - f1.height, f1.contentY + p))
}
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
Flickable {
id: f2
width: 50
height: main.height
contentHeight: contentItem.childrenRect.height
interactive: false
Connections {
target: jogger
onScroll: f2.contentY = Math.max(0, Math.min(f2.contentHeight - f2.height, f2.contentY + p))
}
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
MouseArea {
id: jogger
width: 50
height: main.height
drag.target: knob
drag.minimumY: 0
drag.maximumY: main.height - 50
drag.axis: Drag.YAxis
signal scroll(real p)
property real dy: 0
onPressed: dy = mouseY
onPositionChanged: {
scroll(dy - mouseY)
dy = mouseY
}
onScroll: console.log(p)
Rectangle {
anchors.fill: parent
color: "lightgrey"
}
Rectangle {
id: knob
visible: parent.pressed
width: 50
height: 50
color: "grey"
y: Math.max(0, Math.min(parent.mouseY - 25, parent.height - height))
}
}
}
"jog" 方法的另一个优点是它不是相对的而是绝对的。这意味着如果你的视图很大,如果你使用滚动条,即使是单个像素也可能导致内容发生很大的变化,而在绝对模式下工作的慢跑将始终滚动相同数量的像素,而不管内容大小,这是在需要精度的地方很方便。
您可以将 Flickable
与 Columns
一起使用。
我不知道你的 Columns
是如何水平放置的,但如果它们在 Row
内,那就很简单了:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Multi Column")
Flickable {
anchors.fill: parent
contentWidth: row.implicitWidth
contentHeight: row.implicitHeight
Row {
id: row
Column {
spacing: 5
Repeater {
model: 20
delegate: Rectangle {
width: 50
height: 50
color: "red"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
Column {
spacing: 5
Repeater {
model: 30
delegate: Rectangle {
width: 50
height: 50
color: "cyan"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
ScrollBar.vertical: ScrollBar { }
}
}
即使他们不在 Row
中,您也可以:
contentHeight: Math.max(column1.height, column2.height, ...)
演示: