Попытка программно центрировать элементы в ListView

Я хотел бы иметь центрированные элементы в QML ListView, и поэтому я добавил следующий код моего ListView:

import QtQuick 2.0
import QtMultimedia 5.5
import QtQuick.Controls 1.3
import QtQuick.Extras 1.4
import QtQuick.Layouts 1.2
import QtQuick.Window 2.2
import QtTest 1.1

Rectangle {
    id: ueKeypad

    width: ueMainColumnLayout.implicitWidth+2*radius
    height: ueMainColumnLayout.implicitHeight+2*radius

    color: "grey"

    radius: 8

    border.color: "#99c6f0"
    border.width: 4

    ColumnLayout {
        id: ueMainColumnLayout

        anchors.fill: parent
        anchors.margins: radius

        spacing: 4

        RowLayout {
            id: ueTextLayout

            Text {
                id: ueStaffLoginText

                text: qsTr("Staff Login")

                verticalAlignment: Text.AlignVCenter
                horizontalAlignment: Text.AlignHCenter

                font.family: "Padauk"
                textFormat: Text.RichText

                font.pointSize: 16
                font.bold: true

                color: ueKeypad.border.color

                Layout.fillWidth: true
            }   // ueStaffLoginText
        }   // ueTextLayout

        RowLayout {
            id: uePeopleViewLayout

            ListView {
                id: uePeopleView

                keyNavigationWraps: true

                spacing: 4

                antialiasing: true

                model: uePeopleModel

                Layout.fillWidth: true
                Layout.fillHeight: false

                //Layout.minimumWidth: 64
                Layout.minimumHeight: 64
                //Layout.preferredWidth: 96
                Layout.preferredHeight: 96
                //Layout.maximumWidth: 128
                Layout.maximumHeight: 128

                orientation: ListView.Horizontal
                layoutDirection: Qt.LeftToRight

                snapMode: ListView.SnapToItem

                highlightRangeMode: ListView.ApplyRange

                Component.onCompleted: {
                    var newIndex=(count%2==0)?(count/2):(Math.round(count/2));

                    positionViewAtIndex(newIndex, ListView.Center);
                    currentIndex=newIndex;
                    print(newIndex)
                }   // onCompleted - center items

                delegate: Rectangle {
                        id: uePersonDelegate

                        width: 32
                        height: 32

                        ColumnLayout {
                            id: uePersonDelegateMainLayout

                            anchors.fill: parent
                            anchors.margins: radius

                            RowLayout {
                                id: uePersonDelegateImageLayout

                                Image {
                                    id: uePersonImage

                                    antialiasing: true

                                    fillMode: Image.PreserveAspectFit

                                    source: "image://uePeopleModel/"+model.ueRoleImage
                                }   // uePersonImage
                            }   // uePersonDelegateImageLayout

                            RowLayout {
                                id: uePersonDelegateNameLayout

                                Text {
                                    id: ueTextPersonName

                                    color: "#ffffff"

                                    text: model.ueRoleName

                                    font.bold: true
                                    font.pixelSize: 16

                                    verticalAlignment: Text.AlignVCenter
                                    horizontalAlignment: Text.AlignHCenter
                                }   // ueTextPersonName
                            }   // uePersonDelegateNameLayout
                        }   // uePersonDelegateMainLayout
                    }   // uePersonDelegate

                add: Transition {
                    NumberAnimation {
                        property: "opacity";
                        from: 0;
                        to: 1.0;
                        duration: 100
                    }   // NumberAnimation

                    NumberAnimation {
                        property: "scale";
                        from: 0;
                        to: 1.0;
                        duration: 100
                    }   // NumberAnimation
                }   // Transition

                displaced: Transition {
                    NumberAnimation {
                        properties: "x,y";
                        duration: 100;
                        easing.type: Easing.OutBounce
                    }   // NumberAnimation
                }   // Transition
            }   // uePeopleView
        }   // uePeopleViewLayout

        RowLayout {
            id: ueTumblerLayout

            Tumbler {
                id: ueLoginKeypadTumbler

                Layout.fillWidth: true
                Layout.fillHeight: false

                height: 100

                antialiasing: true

                TumblerColumn {
                    id: ueNumericTumblerColumnDigit1000

                    model: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                }   // ueNumericTumblerColumnDigit1000

                TumblerColumn {
                    id: ueNumericTumblerColumnDigit100

                    model: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                }   // ueNumericTumblerColumnDigit100

                TumblerColumn {
                    id: ueNumericTumblerColumnDigit10

                    model: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                }   // ueNumericTumblerColumnDigit10

                TumblerColumn {
                    id: ueNumericTumblerColumnDigit1

                    model: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
                }   // ueNumericTumblerColumnDigit1
            }   // ueLoginKeypadTumbler
        }   // ueTumblerLayout

        RowLayout {
            id: ueButtonsLayout

            Button {
                id: ueButtonLogin

                Layout.fillWidth: true

                text: qsTr("Login")
            }   // ueButtonLogin

            Button {
                id: ueButtonClear

                Layout.fillWidth: true

                text: qsTr("Clear")
            }   // ueButtonClear

            Button {
                id: ueButtonQuitApp

                Layout.fillWidth: true

                text: qsTr("Quit")
            }   // ueButtonQuitApp
        }   // ueButtonsLayout
    } // ueMainColumnLayout

    states: [
        State {
            name: "ueStateLoginOk"

            PropertyChanges {
                target: ueKeypad
                border.color: "#00ff00"
            }

            PropertyChanges {
                target: ueLoginText
                color: "#00ff00"
            }
        },  // ueStateLoginOk

        State {
            name: "ueStateLoginOkFailed"

            PropertyChanges {
                target: ueKeypad
                border.color: "#ff0000"
            }

            PropertyChanges {
                target: ueLoginText
                color: "#ff0000"
            }
        }   // ueStateLoginOkFailed
    ]   // states
}   // ueKeypad

Теперь оператор print(newIndex) выводит правильное значение 3 (в моем случае, поскольку на данный момент у меня есть 5 элементов), и я хотел бы, чтобы 3-й элемент находился в центре ListView, а два других элемента — слева и справа. . Это возможно? А вне рамок этого вопроса, почему Transitions тоже не работает, взято из примера?

Я также установил highlightRangeMode: ListView.ApplyRange, взятый из подсказки комментария.

Вот скриншот проблемы:

Элементы QML не центрированы


person KernelPanic    schedule 30.08.2015    source источник


Ответы (1)


Проблема здесь в том, что вы пытаетесь разместить ListView делегатов в соответствии с вашими потребностями. Это совершенно неправильно, так как ListView (как и все остальные виды) предназначено для того, чтобы делать это за вас, в соответствии с размером ListView. ListView будет всегда использовать все доступное пространство, в результате чего все делегаты будут располагаться слева, как вы уже поняли.

Вместо того, чтобы навязывать поведение делегатам, вы должны ограничить размер ListView и расположить его в центре. Затем вы можете использовать highlightRangeMode с preferredHighlightBegin и preferredHighlightEnd из этого ответа, чтобы убедиться, что текущий выбранный Item находится в центре списка. . Кроме того, используя StrictlyEnforceRange, вы можете заставить выбранный Item оставаться всегда в центре, что приведет к тому, что IMO будет лучше выбирать желаемый Item.

Вот пример реализации этого подхода. Размеры жестко закодированы для простоты, но могут быть легко параметризованы. Как уже было сказано, я пошел немного дальше, настроив политику выделения. Надеюсь, поможет.

import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1

Window {
    id: win
    width: 300
    height: 300
    visible: true

    ColumnLayout {
        anchors.fill: parent

        Rectangle {
            Layout.fillWidth: true
            Layout.fillHeight: true
            color: "blue"
        }

        ListView {
            Layout.alignment: Qt.AlignCenter
            Layout.minimumWidth: 30 * 5 + 40
            Layout.preferredHeight: 50
            clip: true
            spacing: 15
            model: 10
            orientation: ListView.Horizontal
            delegate: Item {
                width: 30
                height: 50
                Rectangle{
                    anchors.centerIn: parent
                    color: parent.ListView.isCurrentItem ? "red" : "steelblue"
                    width: 30
                    height: 30
                    Text {
                        text: index
                        anchors.centerIn: parent
                    }
                    scale: parent.ListView.isCurrentItem ? 1.5 : 1
                    Behavior on scale { NumberAnimation { duration: 200 } }
                }
            }
            preferredHighlightBegin: width / 2 - 15
            preferredHighlightEnd: width / 2 + 15
            highlightRangeMode: ListView.StrictlyEnforceRange
            Component.onCompleted: currentIndex = count / 2
        }

        Rectangle {
            Layout.fillWidth: true
            Layout.fillHeight: true
            color: "yellow"
        }
    }
}

введите описание изображения здесь

person BaCaRoZzo    schedule 03.09.2015
comment
должно ли это также работать для вертикального ListView? - person KernelPanic; 03.10.2015
comment
@KernelPanic его следует адаптировать для учета высоты, а не ширины, но основные шаги есть. Я думаю, вы должны найти что-то подобное на SO (или, по крайней мере, я помню, что давал ответ для вертикального ввода... но может ошибаться). - person BaCaRoZzo; 03.10.2015