内容居中的流式布局

Flow layout with centered content

当 window 宽度太小而无法在一行中显示所有项目时,我有一行项目应该堆叠,如下图所示:

Flow 组件堆叠项目但它们不居中而是在左侧或右侧对齐:

Flow {
    Item {}
    Item {}
    Item {}
    Item {}
    Item {}
}

QML 中是否有内置方法使流居中?

另一个非常相似的用例是让初始的、较小的流也水平居中:

import QtQuick 2.0
import QtQuick.Controls 2.0

ApplicationWindow {
    id: window
    width: 600
    height: 600
    visible: true

    Slider {
        id: slider
        value: 10
        to: 100
        stepSize: 1
        width: parent.width
        anchors.bottom: parent.bottom
    }

    Flow {
        id: flow
        width: Math.min(implicitW, maxW)
        spacing: 4
        anchors.horizontalCenter: parent.horizontalCenter

        readonly property int columnImplicitWidth: children[0].implicitWidth + spacing
        readonly property int implicitW: Math.max(0, (repeater.count * columnImplicitWidth) - spacing)
        readonly property int maxW: Math.floor(parent.width / columnImplicitWidth) * columnImplicitWidth

        Repeater {
            id: repeater
            model: slider.value
            delegate: Rectangle {
                implicitWidth: 40
                implicitHeight: 60
                color: "transparent"
                border.color: "darkorange"
            }
        }
    }

    Rectangle {
        anchors.fill: flow
        color: "transparent"
        border.color: "red"
    }
}

我认为 GridLayout 对此更好,因为与 Flow 不同,它不会在右边缘留下额外的 space:

import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

ApplicationWindow {
    id: window
    width: 600
    height: 600
    visible: true

    Slider {
        id: slider
        value: 10
        to: 100
        stepSize: 1
        width: parent.width
        anchors.bottom: parent.bottom
    }

    GridLayout {
        columns: implicitW < parent.width ? -1 : parent.width / columnImplicitWidth
        rowSpacing: 4
        columnSpacing: 4
        anchors.horizontalCenter: parent.horizontalCenter

        property int columnImplicitWidth: children[0].implicitWidth + columnSpacing
        property int implicitW: repeater.count * columnImplicitWidth

        Repeater {
            id: repeater
            model: slider.value
            delegate: Rectangle {
                implicitWidth: 40
                implicitHeight: 60
                color: "transparent"
                border.color: "darkorange"
            }
        }
    }
}

这是 GridLayout 的样子:

我认为没有任何内置方法可以这样做。您必须制作自己的元素。

嗯,没有内置方法,但我找到了解决方法。

想法很简单,因为Flow is already an Item it has anchors.leftMargin and anchors.rightMargin。因此,如果我们可以计算,Flow 行内有多少元素,那么我们就可以计算出左右边距。这样我们就可以居中了。

这是一个简单的代码,

        Flow {
        property int rowCount: parent.width / (elements.itemAt(0).width + spacing)
        property int rowWidth: rowCount * elements.itemAt(0).width + (rowCount - 1) * spacing
        property int mar: (parent.width - rowWidth) / 2

        anchors {
            fill: parent
            leftMargin: mar
            rightMargin: mar
        }

        spacing: 6
        Repeater {
            id: elements
            model: 5
            Rectangle {
                color: "#aa6666"
                width: 100; height: 100
            }
        }

CenterFlow.qml

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.3

Rectangle{
    implicitHeight: elements.height
    default property alias content: elements.children
    property int flowSpacing: 0
    color: "transparent"
    Flow{
        function mar(){
            var rowCount = parent.width / (elements.children[0].width + flowSpacing);
            if(rowCount> elements.children.length){
                rowCount = elements.children.length
            }
            rowCount = parseInt(rowCount)
            var rowWidth = rowCount * elements.children[0].width + (rowCount - 1) * flowSpacing
            print(elements.height)
            return (parent.width - rowWidth) / 2

        }
        spacing: flowSpacing
        id:elements
        leftPadding: mar()
        rightPadding: mar()
        width: parent.width
    }
}

这样使用:

CenterFlow {
     id:centerFlow
     flowSpacing: 10
     width: parent.width -10*2

     Button{

     }
     Button{

    }
}

AFAICT,以前的答案并没有真正回答问题。它们似乎只将 flow/grid 本身居中,而不是将其中的元素居中。只要只有 1 行,项目就会居中。对于多行,它们只会从左到右填充最后一行。所以这是一种始终将项目居中的方法:

        Flow {
            id: flow
            Layout.fillWidth: true

            property int columns: 3
            property int cellWidth: width / columns
            property int totalRows: flowRepeater.count / columns

            Repeater {
                id: flowRepeater
                model: 5
                delegate: Rectangle {
                    id: flowDelegate
                    width: Math.floor(flow.width / itemsInRow)
                    height: 100
                    color: "transparent"
                    border.width: 1
                    border.color: "red"
                    property int row: Math.floor(index / flow.columns)
                    property int itemsInRow: row < flow.totalRows ? flow.columns : (flowRepeater.count % flow.columns)

                    Rectangle {
                        color: "blue"
                        height: 80
                        width: height
                        radius: width / 2
                        anchors.centerIn: parent
                    }
                }
            }
        }