QML中ListView數據的分組與定位顯示

在QML中ListView的數據分組與定位顯示時,以前使用ListView進行數據分組時,都是在model中加入分組數據(分組的項),然後將model中的數據排好序後全部顯示到ListView中,這樣做也能達到數據分組的目的,但是數據維護太費力,我們自己好做的事情太多,埋下的隱藏問題也就越多。
這次介紹ListView自身的藝術section屬性,可以達到數據分組顯示的作用,通過設置如下三個屬性:
section.property: "name";
section.criteria: ViewSection.FirstCharacter
section.delegate: sectionHeader
然後實現分組顯示的代理sectionHeader,如下:
Component {
        id:sectionHeader
        Rectangle {
            width: parent.width
            height: 20
            color: "steelblue"
            Label {
                text: section
                font.bold: true
                font.pixelSize: 20
                anchors.left: parent.left
                anchors.leftMargin: 10
            }
        }
    }
設置了分組的顯示樣式,即可實現通過model中的name字段的首字母進行分組顯示。話不多說先上圖,其初步效果如下:

這裏需要注意的是,雖然我們不需要對分組項(上圖中的藍色項)進行管理,但是我們需要對ListModel中要顯示數據進行排序管理,不然會出現多個分組,也就是說,section不會自動排序,相同section的model數據必須放在連續的一塊,不然的話,不連續的section會分別進行顯示,這一點要特別注意(即使這樣,也比以前所有的項全都自己管理強的多^_^)。
實現了以上功能後,還想模仿手機的聯繫人列表,通過右側的字母進行ListView的定位,如下先展示其完整代碼:
import QtQuick 2.5
import QtQuick.Layouts 1.2
import QtQuick.Controls 1.4
import Qt.labs.controls 1.0
import QtQuick.Controls.Styles 1.4


Rectangle {
    id: root
    width: 800
    height: 600
    Component {
        id:sectionHeader
        Rectangle {
            width: parent.width
            height: 20
            color: "steelblue"
            Label {
                text: section
                font.bold: true
                font.pixelSize: 20
                anchors.left: parent.left
                anchors.leftMargin: 10
            }
        }
    }


    Rectangle {
        width: 200
        height: 300
        anchors.centerIn: parent
        color: "grey"


        ListView {
            id: list_view
            anchors.fill: parent
            clip: true
            anchors.margins: 5
            model: list_model
            delegate: Rectangle {
                height: 30
                width: parent.width
                Label {
                    text: name
                    anchors.centerIn: parent
                    color: "green"
                }
            }


            section.property: "name";
            section.criteria: ViewSection.FirstCharacter//ViewSection.FullString
            section.delegate: sectionHeader


            ScrollBar.vertical: ScrollBar {
                id: scrollBar
                onActiveChanged: {
                    active = true;
                }
                Component.onCompleted: {
                    scrollBar.handle.color = "red";
                    scrollBar.active = true;
                    scrollBar.handle.width = 10;
                }
            }
        }


        Rectangle {
            id: lab
            width: 30
            height: width
            color: "red";
            radius: width/2
            opacity: 0.8
            anchors.centerIn: parent
            Label {
                id: curLabel
                font.pixelSize: 26
                font.bold: true
                anchors.centerIn: parent
            }
            visible: false
        }


        Rectangle {
            width: 10
            height: parent.height-100
            anchors.right: parent.right
            anchors.rightMargin: 10
            color: "transparent"
            anchors.verticalCenter: parent.verticalCenter
            Column {
                anchors.centerIn: parent
                spacing: 3
                clip: true
                Repeater {
                    model: ["a","b","c","d","e","f","g","h","i","j","k"]
                    Label {
                        text: modelData
                        font.pixelSize: 16
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter


                        MouseArea {
                            anchors.fill: parent
                            hoverEnabled: true
                            onEntered: {
                                console.log("onClicked:", modelData);
                                var idx = getIndexFromLab(modelData);
                                list_view.positionViewAtIndex(idx, ListView.Beginning)


                                lab.visible = true;
                                curLabel.text = modelData
                            }
                            onExited: lab.visible = false;
                        }
                    }
                }
            }
        }
    }


    function getIndexFromLab(lab)
    {
        var i;
        for (i=0;i<list_model.count;i++)
        {
            if (list_model.get(i).name.substr(0, 1) === lab)
            {
                return i;
            }
        }
        return i<=11?i:7;
    }


	//測試數據
    ListModel{
        id:list_model
        ListElement {
            name: "aItem1"
        }
        ListElement {
            name: "aItem2"
        }
        ListElement {
            name: "aItem3"
        }
        ListElement {
            name: "bItem4"
        }
        ListElement {
            name: "bItem5"
        }
        ListElement {
            name: "cItem6"
        }
        ListElement {
            name: "cItem7"
        }
        ListElement {
            name: "tItem8"
        }
        ListElement {
            name: "tItem9"
        }
        ListElement {
            name: "tItem10"
        }
        ListElement {
            name: "wItem11"
        }
        ListElement {
            name: "wItem12"
        }
        ListElement {
            name: "wItem13"
        }
        ListElement {
            name: "zItem14"
        }
        ListElement {
            name: "zItem151"
        }
    }
}
以上代碼中,不僅實現了model中數據的分組,還通過鼠標滑動到右側的字母上時自動定位ListView的顯示,主要使用了Repeater控件進行分組字母的顯示,通過計算鼠標當前在Repeater中的那個字母上,得出ListView中應該展示的索引(這裏沒有進行詳細的計算,只是初步計算,要想精確定位,在這塊還得繼續優化,請參見下一篇JS遞歸調用定位ListView應該定位的項),然後調用ListView的positionViewAtIndex(idx, ListView.Beginning)進行顯示的定位,其實現效果如下:

​如上圖,當鼠標在"c"上時,分組自動定位到C分組,中間的紅圓形顯示當前顯示分組的字母,這樣,完美實現了數據的分組顯示與定位^_^。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章