流的反向布局顺序


我希望有Flow

对象从左到右添加,但每一行都向右对齐。

import QtQuick 2.0
import QtQuick.Controls 2.0
Flow {
width: 400
anchors.right: parent.right
spacing: 2
Repeater {
model: ['a', 'b', 'c', 'd', 'e', 'f', 'g']
delegate: Button {
text: modelData
width: (83 * (model.index + 1)) % 100 + 30
}
}
}

Flow向右对齐,但其中的行将始终从Flow的左边缘开始。我可以设置

layoutDirection: Qt.RightToLeft

这会将行向右对齐,但项目的顺序也会颠倒。

如果我反转模型(在这个例子中可以通过调用reverse()ListModel我需要反转ProxyModel(,a会向左,但行顺序不对。

我怎么能实现这样的东西?

import QtQuick 2.5
import QtQuick.Controls 2.1
ApplicationWindow {
id: root;
width: 640
height: 480
visible: true
Rectangle {
z: -1
color: "#80000000"
width: flow.width
height: flow.height
anchors.centerIn: flow
}
Flow {
id: flow
width: 400
anchors.right: parent.right
spacing: 2
Repeater {
id: repeater
property real remainingRowSpace: flow.width
property real indexOfFirstItemInLastRow: 0
model: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q']
delegate: Rectangle {
property real buttonWidth: (83 * (model.index + 1)) % 100 + 30
color: "#80000000"
width: buttonWidth
height: childrenRect.height
Button {
x: parent.width - width
text: modelData
width: parent.buttonWidth
}
}
onItemAdded: {
var spacing = parent.spacing
// Check if new row.
if (item.width > remainingRowSpace) {
// Increase width of first item push row right.
itemAt(indexOfFirstItemInLastRow).width += remainingRowSpace
// Reset available space
remainingRowSpace = parent.width
// Store index of item
indexOfFirstItemInLastRow = index
// Don't need to subtract spacing for the first item
spacing = 0
}
remainingRowSpace -= (item.width + spacing)
// Handle when no more rows will be created.
if (index === repeater.count - 1) {
itemAt(indexOfFirstItemInLastRow).width += remainingRowSpace
}
}
}
}
}

这不是一个非常通用或动态的解决方案,但它有效。

这仍然是一项正在进行的工作,但可能仍然适用于某些人

就像托尼·克利夫顿(Tony Clifton(的解决方案一样,它使用Repeater并且是onItemAdded方法,但使用Qt.binding来保持事物的动态性它并不优于托尼·克利夫顿的解决方案,选择可能取决于用例。

优点:

  • 动态更改单个Item宽度
  • 动态到反向流的宽度

缺点:

  • 首先填充底行。第一行可能没有满(对于某些用例,这可能更好(

当与ListModel一起使用并且正在insert()新条目时,这两种解决方案都不起作用。当模型被完全替换时,这两种解决方案都应该有效(例如,使用JSArrays 和手动调用modelChanged()(。

从某种意义上说,这两种解决方案都不Flow,您可以在Repeater处理布局时放入任意对象。因此,Repeater必须创建Item。我没有让它与ObjectModel一起工作.摆脱中继器将是我最后关心的问题。

Item {
id: root
visible: false
width: 400
height: (rep.count > 0 ? rep.itemAt(0).y * -1 : 0)
anchors.centerIn: parent
property real spacing: 5
Item {
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
Repeater {
id: rep
model: ListModel {
id: bm
ListElement { text: "a" }
ListElement { text: "b" }
ListElement { text: "c" }
ListElement { text: "d" }
ListElement { text: "e" }
ListElement { text: "f" }
ListElement { text: "g" }
ListElement { text: "h" }
ListElement { text: "i" }
}
onItemAdded: {
console.log(index, item, itemAt(index - 1))
item.anchors.right = Qt.binding(
function() {
if (rep.count === index + 1) return parent.right
var neighbor = rep.itemAt(index + 1)
if (neighbor.x - item.width - root.spacing < 0) return parent.right
return rep.itemAt(index + 1).left
}
)
item.anchors.bottom = Qt.binding(
function() {
if (rep.count === index + 1) return parent.bottom
var neighbor = rep.itemAt(index + 1)
if (neighbor.x - item.width - root.spacing < 0)
return neighbor.top
return neighbor.bottom
}
)
item.anchors.rightMargin = Qt.binding(
function() {
return (item.anchors.right === parent.right ? 0 : root.spacing)
}
)
item.anchors.bottomMargin = Qt.binding(
function() {
return (item.anchors.bottom === rep.itemAt(index + 1).top ? root.spacing : 0)
}
)
}
delegate: Button {
text: modelData
property int count: 0
width: (83 * (index + count + 1)) % 100 + 30
onClicked: {
count++
}
}
}
}
Rectangle {
id: debug
anchors.fill: parent
color: 'transparent'
border.color: 'red'
}
}

这背后的想法是在添加对象时初始化锚点的绑定,如果有足够的空间,我将每个Item锚定到右侧或其后继者。
如果它紧挨着他,我还会将Item的底部锚定在它的后继者底部,或者如果它开始新行,则锚定在它的顶部。如果它没有后继项,它将锚定到父项的底部。
后一个事实使得这个带有两个封闭Item的奇怪结构是必要的。外部将真正包围一切,并动态增长,但这不可能是我锚定整个链条的那个,就像我锚定在底部一样。如果我根据childrenRect.height更改height,我将以具有奇怪效果的绑定循环结束,因为 Items 的 y 值不会保持不变。最初它会工作,但是当物品由于尺寸变化而移动时,它会破裂。

相关内容

  • 没有找到相关文章

最新更新