QML ListView - 更改除当前项目以外的所有项目

QML ListView - change all but current item

我在使用 Qt 5.7[=55= 时正在关注 Qt 4.8this 教程(每个条目中没有可滑动的内容) ] 与 QtQuick 2.0ListView 的工作方式如下:

  1. 用户点击列表中的项目
  2. 显示项目的替代(详细)视图
  3. 用户必须在详细视图中单击 Close 按钮才能将条目状态重置为其默认的紧凑视图。

这会导致混乱,在某些时候,如果用户单击所有项目,在这种情况下,所有项目都会以完整视图显示。每次 he/she 打开详细视图时让用户单击 Close 按钮也不是那么方便。

我已将条目更改为在用户单击视图时关闭。我也在努力防止这种混乱并实现更(omho)流动的行为:

  1. 用户点击列表中的项目
  2. 显示项目的替代视图
  3. 用户单击详细视图以将条目状态重置为其默认的紧凑视图
  4. 用户单击另一个条目,所有当前在详细视图中的条目都将重置为其紧凑视图

目前我正在遍历 ListViewcontentItem.children[loop_index] 并将状态设置为 """Details" = 显示详细视图 | "" = 显示紧凑视图)。由于 ListView 的工作方式(loading/unloading 按需委托),这是非常不可靠的,当我尝试访问其他委托的状态时,我经常得到未定义的引用。以下 MouseArea,我用来做所有这些,是每个委托的一部分:

// state is a QML `State` that is bound to the delegate (see below for the details on it)
MouseArea {
    anchors.fill: background
    onClicked: {
        // Iterate through all other entries and close them
        for (var entry = 0; entry < listView.count; ++entry) {
            if(listView.contentItem.children[entry] !== gestureEntry) {
                console.log("Hide other element");
                listView.contentItem.children[entry].state = ""; // IT FAILS HERE (SOMETIMES)
            }
        }

        // Change view of current entry
        if(gestureEntry.state === "Details") {
            gestureEntry.state = "";
            console.log("Hiding details")
        }
        else {
            gestureEntry.state = "Details";
            console.log("Showing details");
        }
    }
}

其中 state 是代表的状态:

states: State {
    name: "Details"

    PropertyChanges { target: background; color: "white" }
    PropertyChanges { target: gestureImage; width: 130; height: 130 } // Make picture bigger
    PropertyChanges { target: gestureEntry; detailsOpacity: 1; x: 0; y: 0 } // Make details visible
    PropertyChanges { target: gestureEntry; height: listView.height } // Fill the entire list area with the detailed view
}

我认为 state 信息可以存储在 ListModel 本身中,从而可以遍历模型的内容(与委托的内容不同,它们始终存在)我不知道如何在模型中的条目更改时自动更新我的列表(以及当前的 visible/invisible 代表)。到目前为止我发现似乎不可能这样做,因为 ListView 没有主动监控它的 ListModel.

真的是这样吗?如果是,那么是否可以用不同的方式解决这个问题?

为什么不使用 ListViewcurrentIndex 属性? 只需像这样修改您的代表:

Item {
    id: gestureEntry
    ...
    state: ListView.isCurrentItem?"Details":""
    ...
    MouseArea {
        anchors.fill: background
        onClicked: {
            if(listView.currentIndex == index)
                listView.currentIndex = -1
            else
                listView.currentIndex = index
        }
    }
}

编辑: 上述解决方案的唯一问题是 - 在加载时 - 预选了 ListView 中的条目,这会自动触发该条目的详细视图。为了避免需要在 listView 中添加以下内容:

Component.onCompleted: {
    listView.currentIndex = -1;
}

这确保不会预选任何条目。

我猜这是一个问题,因为您在委托中存储了一个状态。您不应按照 delegate-属性 (Link) 中的描述执行此操作,因为委托在离开视图时会被重用。

至少你应该在 State 中使用一个 when: ListView.isCurrentItem 并依赖于 ListView 的一个值。所以只有你当前的委托被最大化。然后在 MouseArea 中只设置 `ListView.view.currentIndex = index'。 不要在函数中手动改变状态!

我运行遇到了同样的麻烦,完全删除了状态,只使用了附件属性ListView.isCurrentItem。但是将状态绑定到 ListView 中的值也应该有效,因为它没有存储在委托中。

最小示例:

import QtQuick 2.0

Item {
    width: 800
    height: 600

    ListView {
        id: view
        anchors.fill: parent
        model: 3
        spacing: 5
        currentIndex: -1
        delegate: Rectangle {
            id: delegate
            color: ListView.isCurrentItem ? "lightblue" : "green" // directly change properties depending on isCurrentItem
            height: 100
            width: 100

            states: State {
                name: "maximized"
                when: delegate.ListView.isCurrentItem // bind to isCurrentItem to set the state
                PropertyChanges {
                    target: delegate
                    height: 200
                }
            }
            MouseArea {
                anchors.fill: parent
                //onClicked: delegate.ListView.view.currentIndex = model.index // if only selection is wanted
                onClicked: {
                    //console.debug("click");
                    if (delegate.ListView.isCurrentItem)
                    {
                        delegate.ListView.view.currentIndex = -1;

                    }
                    else
                    {
                        delegate.ListView.view.currentIndex = model.index;
                    }
                }
            }
            Text {
                anchors.centerIn: parent
                text: index
            }
        }
        Text {
            text: "CurrentIndex: " + parent.currentIndex
        }
    }
}